<?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: Khe Ai</title>
    <description>The latest articles on DEV Community by Khe Ai (@kheai).</description>
    <link>https://dev.to/kheai</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%2F789591%2F20f5f929-80e6-456f-b891-efb5be57c07a.jpeg</url>
      <title>DEV Community: Khe Ai</title>
      <link>https://dev.to/kheai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kheai"/>
    <language>en</language>
    <item>
      <title>Founding Lead Playbook: Running Product, Architect &amp; Engineering with AI Agents + 2 Humans</title>
      <dc:creator>Khe Ai</dc:creator>
      <pubDate>Thu, 16 Jul 2026 14:33:50 +0000</pubDate>
      <link>https://dev.to/kheai/founding-lead-playbook-running-product-architect-engineering-with-ai-agents-2-humans-295d</link>
      <guid>https://dev.to/kheai/founding-lead-playbook-running-product-architect-engineering-with-ai-agents-2-humans-295d</guid>
      <description>&lt;p&gt;There are a lot of shallow "10x with AI" threads out there. This isn't one of them. This is the actual operating model I use to run product, architecture, and backend engineering as a single person, with one human collaborator (a frontend developer) and an AI coding agent doing the heavy lifting on everything else.&lt;/p&gt;

&lt;p&gt;The premise: a stakeholder hands me a one-sentence goal. From there, I own product definition, system design, and technical execution end to end. I have exactly one other human in the loop. Everything else — backend, migrations, tests, infra scripts — runs through an AI coding agent that I direct, review, and gate.&lt;/p&gt;

&lt;p&gt;The honest answer to "does this scale" is: yes, but only if you restructure how you work, not just what tools you use. Bolting an AI agent onto a traditional PM → architect → engineer pipeline doesn't collapse the timeline — it just moves the bottleneck to your own attention. Here's the actual playbook, including the parts that broke before I fixed them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/kheai/blog/260716-super-lead.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F395y08yr4bp9i5obr46g.png" alt="From 4 FTEs to 1: How I Run PM, PO, SA, and TL (and Keep My Frontend Dev Sane) with Claude Code" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The core shift: latency drops, judgment doesn't
&lt;/h2&gt;

&lt;p&gt;In a multi-person team, a lot of calendar time goes to reconciling context between people — PRD reviews, architecture alignment, ticket grooming. Collapse those roles into one person and that &lt;em&gt;coordination&lt;/em&gt; latency mostly disappears. What doesn't disappear, and what people underestimate, is the judgment load: you still have to make every product call, every architectural tradeoff, and every "is this actually correct" review — just faster and back-to-back.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2qo1xs4oikqsxeaz212q.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2qo1xs4oikqsxeaz212q.png" alt="Super Tech Lead Flow" width="800" height="1076"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You still own the architecture, the product vision, and the final quality gate. The agent owns boilerplate, migration scripts, test scaffolding, and the first draft of business logic. The frontend developer owns UI/UX and interaction — and should never be blocked waiting on you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: The execution loop, phase by phase
&lt;/h2&gt;

&lt;p&gt;The single biggest failure mode in this model is context-switching mid-thought — writing code while you're still deciding what the feature even is. Treat each phase as a distinct mode with a distinct output artifact, and don't move to the next phase until the current one has a concrete deliverable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1 — Product definition: decouple "what" from "how".&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a vague goal lands (e.g. "we need a multi-tenant billing aggregator"), resist opening the editor. First pass is product framing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Analyze this objective. Strip vanity features. What are the 3 core user flows that define the MVP? What are the day-one edge cases we can't defer?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Treat the agent's output as a first draft, not a spec — it will over-scope and hallucinate requirements that sound plausible but weren't asked for. Your job is subtractive: cut it down to a backlog of user stories you'd actually defend to a stakeholder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 2 — System design: harden the schema and the contract before any code exists.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The artifacts that matter here are the data schema and the API contract — not diagrams for their own sake. A concrete prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Design a PostgreSQL schema for these user stories. Every tenant-owned table needs an explicit &lt;code&gt;tenant_id&lt;/code&gt; foreign key, not just an implicit assumption of isolation. Generate the migration. Then produce an OpenAPI 3.0 spec for the endpoints, and flag which mutating endpoints need idempotency keys."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One correction worth making explicit: Postgres Row-Level Security (&lt;code&gt;CREATE POLICY&lt;/code&gt;) is a real and valid tenant-isolation mechanism, but it's not the only one, and for most application-layer multi-tenancy, filtering by an indexed &lt;code&gt;tenant_id&lt;/code&gt; column &lt;em&gt;at the service layer&lt;/em&gt; — never trusting the client for that value, always deriving it from an authenticated token — is simpler to reason about and test than RLS policies that live outside your application code and are easy to forget to enable on a new table. Pick one mechanism deliberately and apply it uniformly; the actual bug that bites teams isn't "which mechanism," it's the one table someone forgot to scope.&lt;/p&gt;

&lt;p&gt;Once you approve the schema and contract, that OpenAPI document becomes the single source of truth for both the backend implementation and the frontend integration. Nobody should be inferring the contract from someone else's code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 3 — Execution: agentic implementation against a locked contract.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the contract locked, point the agent at it directly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Implement the endpoints in &lt;code&gt;billing-openapi.yaml&lt;/code&gt;. Write integration tests alongside the implementation, not after. Mock the third-party payment gateway. Every soft-deletable entity must be excluded from lookups by default — verify this with a test, not a comment."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Watch it iterate — writing routes, wiring the data layer, running its own tests until they pass. Your job shifts to review: does the generated code actually implement the invariant you asked for, or does it look right at a glance and fall apart under a concurrent-write or soft-delete edge case? This is the phase where unverified trust in agent output causes the most expensive bugs — see Trap 1 below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 4 — The frontend handshake: never let the human be the bottleneck.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While the agent works the backend, your frontend developer should never be idle waiting for a real server to exist. The fix is a fast fake:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Spin up a mock server (e.g. Prism) directly from the OpenAPI spec.&lt;/li&gt;
&lt;li&gt;Generate TypeScript types from that same spec and hand them over — not written by hand, always derived from the contract so they can't silently drift from it.&lt;/li&gt;
&lt;li&gt;Hand off a ticket with: UI requirements, the exact endpoint contracts, the generated types, and the mock server URL.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The frontend developer builds against a fake that behaves exactly like the real API's shape will, in parallel with backend implementation — not after it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 5 — Defense-in-depth review before merge.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When both the backend implementation and the frontend PR are ready, run a deliberately adversarial pass — not a rubber stamp:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Audit the newly merged routes for SQL injection risk, unhandled promise rejections, N+1 query patterns, and any endpoint that filters a mutation by ID alone without also checking an ownership/tenant claim."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then do a manual read of the frontend PR, boot the real stack (not just unit tests — actually exercise the flow), and run an integration smoke test end to end. Automated audits catch pattern-matchable classes of bug; they do not catch "this endpoint is logically correct but violates an invariant the codebase depends on elsewhere." That still needs a human who knows the codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: The hidden traps
&lt;/h2&gt;

&lt;p&gt;This looks smooth described linearly. In practice there are three specific failure modes that will bite you if you don't build explicit countermeasures for them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trap 1: Confident-looking code that's quietly wrong
&lt;/h3&gt;

&lt;p&gt;An AI coding agent will produce large amounts of syntactically correct, plausible-looking code very quickly. It has no felt sense of how painful a given shortcut will be to live with in six months, and — more dangerously — it will happily generate code that &lt;em&gt;looks&lt;/em&gt; like it respects an invariant (soft-delete, tenant scoping, transactional atomicity) without actually doing so, because the surface pattern is right even when the substance isn't.&lt;/p&gt;

&lt;p&gt;Concrete example of the failure shape: a lookup helper that appears to respect soft-delete because it uses the same repository method as everywhere else, but a nearby "quick fix" swaps in a raw &lt;code&gt;UPDATE&lt;/code&gt;/&lt;code&gt;increment&lt;/code&gt; call that bypasses the ORM's default filtering entirely. Nothing fails at compile time. Nothing fails in a shallow unit test that mocks the repository. It fails in production, quietly, against a real row that should have been excluded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mitigations that actually work:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Small, single-responsibility files and modules.&lt;/strong&gt; Force decomposition — a giant file is where a bypassed invariant hides longest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests written alongside the implementation, not after.&lt;/strong&gt; If the agent can't make its own code pass tests for the exact invariant you care about (soft-delete exclusion, tenant isolation, idempotency), that's a signal the design is under-specified, not that the tests are wrong.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A recurring "what did we bypass" audit.&lt;/strong&gt; Periodically ask explicitly: "grep for direct &lt;code&gt;UPDATE&lt;/code&gt;/&lt;code&gt;increment&lt;/code&gt;/raw-query calls that skip the ORM's default scoping — list every one and justify each." This catches the class of bug that a generic code-quality pass misses, because the code isn't badly written — it's precisely wrong in a way that only matters if you know the invariant it's supposed to uphold.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify claims against the actual entity/schema, not the design doc's own description of it.&lt;/strong&gt; A design document can be internally consistent and still wrong about what the current code does — the only ground truth is the file itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Trap 2: Context-switch fatigue
&lt;/h3&gt;

&lt;p&gt;Jumping between product framing, system design, and low-level debugging every twenty minutes measurably degrades decision quality — you start making sloppy tradeoffs by mid-afternoon because your brain is still half in the previous mode. The fix isn't willpower, it's scheduling:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time block&lt;/th&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Focus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Deep-focus block&lt;/td&gt;
&lt;td&gt;Product &amp;amp; architecture&lt;/td&gt;
&lt;td&gt;Requirements, schema, contracts. No implementation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execution block&lt;/td&gt;
&lt;td&gt;Technical lead&lt;/td&gt;
&lt;td&gt;Directing the agent, reviewing generated code, fixing integration issues.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Admin block&lt;/td&gt;
&lt;td&gt;Backlog &amp;amp; coordination&lt;/td&gt;
&lt;td&gt;Grooming, status updates, unblocking the frontend developer.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Protect the boundaries. Don't let a "quick architecture question" bleed into an execution block, and don't context-switch back to design mid-implementation just because something looks solvable in five minutes — write it down and come back to it in the next design block.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trap 3: The velocity gap between AI-assisted backend and human frontend work
&lt;/h3&gt;

&lt;p&gt;An AI-assisted backend can move several times faster than a human doing frontend implementation and design iteration. If you push that raw velocity downstream unfiltered, your frontend collaborator ends up perpetually behind, context-switching on every drip-fed change, and reasonably start to feel steamrolled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mitigations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Batch, don't drip.&lt;/strong&gt; Bundle backend changes into coherent feature-sized handoffs on a predictable cadence, rather than pushing every incremental change as it lands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write the handoff note yourself.&lt;/strong&gt; Auto-generated API docs describe the &lt;em&gt;shape&lt;/em&gt; of an interface, not how the pieces are meant to fit together or which states are the tricky ones. A few minutes of plain-language context from the person who actually made the design tradeoffs saves hours of the other person reverse-engineering intent from a diff.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 3: Reusable prompt scaffolding
&lt;/h2&gt;

&lt;p&gt;These are the actual system-prompt shapes I keep reusing, generalized so they're useful regardless of stack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture-mode system prompt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;You are acting as a principal-level solution architect for cloud-native systems.
Optimize for security, cost, and long-term maintainability over cleverness.

Rules:
&lt;span class="p"&gt;1.&lt;/span&gt; Prefer a relational database with explicit foreign keys and indexes over
   schemaless flexibility, unless there's a specific reason not to.
&lt;span class="p"&gt;2.&lt;/span&gt; Every tenant-owned or user-owned resource needs an explicit, indexed
   ownership column, checked at the service layer — never trust client input
   for it, always derive it from an authenticated context.
&lt;span class="p"&gt;3.&lt;/span&gt; Favor a modular monolith over microservices until there's a concrete,
   measured scaling reason to split — don't design for hypothetical scale.
&lt;span class="p"&gt;4.&lt;/span&gt; APIs should be stateless; sessions/identity travel in signed tokens, not
   server-side session state.
&lt;span class="p"&gt;5.&lt;/span&gt; Mutating endpoints that could plausibly be retried (payments, anything
   with side effects) need idempotency keys.

Output structured markdown — schema tables, OpenAPI fragments. No filler prose.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pre-merge review prompt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Review this diff as a pedantic, security-focused reviewer. Check specifically for:
&lt;span class="p"&gt;-&lt;/span&gt; Injection risk or any raw query that bypasses the ORM's default scoping
  (soft-delete filters, tenant/owner filters).
&lt;span class="p"&gt;-&lt;/span&gt; Missing error handling, unhandled promise rejections.
&lt;span class="p"&gt;-&lt;/span&gt; N+1 query patterns in data fetches.
&lt;span class="p"&gt;-&lt;/span&gt; Any delete/update filtered by ID alone, without an ownership or tenant check.
&lt;span class="p"&gt;-&lt;/span&gt; Hardcoded secrets or config values.
&lt;span class="p"&gt;-&lt;/span&gt; Any comparison of a secret value (API key, token, signature) using a
  non-constant-time equality check.

For each finding: exact location, severity, and a corrected code block.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The actual reality check
&lt;/h2&gt;

&lt;p&gt;This way of working is genuinely faster — you're not waiting on a meeting to change a column, or a QA cycle to verify a basic endpoint. But the speed is entirely conditional on one thing: your review discipline scaling with your output. An AI coding agent will write code as fast as you can specify it. It will not tell you when the specification itself is wrong, and it will not notice when its own output looks correct but violates an invariant it was never told mattered.&lt;/p&gt;

&lt;p&gt;Your value in this model isn't typing speed — it never really was. It's how precisely you can define the problem, how much of the actual invariant-space of the system you can hold in your head during review, and how well you can keep a human collaborator unblocked while the machine does the parts that don't need taste.&lt;/p&gt;

&lt;p&gt;Wear one hat at a time. Trust but verify, every time, especially when the code looks fine.&lt;/p&gt;

</description>
      <category>kheai</category>
      <category>management</category>
      <category>ai</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>Connecting RooCode to Gemma4-26B-MoE via OpenAI Bridge</title>
      <dc:creator>Khe Ai</dc:creator>
      <pubDate>Tue, 02 Jun 2026 17:33:01 +0000</pubDate>
      <link>https://dev.to/kheai/connecting-roocode-to-gemma4-26b-moe-via-openai-bridge-koi</link>
      <guid>https://dev.to/kheai/connecting-roocode-to-gemma4-26b-moe-via-openai-bridge-koi</guid>
      <description>&lt;p&gt;This configuration bypasses extension UI limitations by routing direct Google AI Studio requests through Google’s native OpenAI-compliant endpoint. This allows you to use newly released or unlisted models like &lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; completely free of charge, without needing a third-party proxy account like OpenRouter.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VS Code&lt;/strong&gt; with the &lt;strong&gt;RooCode&lt;/strong&gt; extension installed.
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Google AI Studio API Key&lt;/strong&gt; (Get one for free at &lt;a href="https://aistudio.google.com/?authuser=1" rel="noopener noreferrer"&gt;aistudio.google.com&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. RooCode Profile Configuration
&lt;/h2&gt;

&lt;p&gt;Open your RooCode settings menu (the gear icon at the top right of the extension pane) and fill out the fields exactly as follows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Setting&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Value to Enter&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Notes&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;API Provider&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OpenAI Compatible&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Standardizes data transport to match Google's bridge.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Base URL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://generativelanguage.googleapis.com/v1beta/openai/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Must include the trailing slash (&lt;code&gt;/&lt;/code&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;API Key&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Your Google AI Studio API Key&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Starts with &lt;code&gt;AIzaSy...&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The exact technical identifier for the model.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model Reasoning Effort&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;None&lt;/code&gt; / &lt;code&gt;Default&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Not natively supported by Gemma models; leave it blank or default.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  3. Why This Works (Troubleshooting Context)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Bridge Endpoint:&lt;/strong&gt; Google provides the &lt;code&gt;/v1beta/openai/&lt;/code&gt; URL block specifically so developers can drop Gemini models seamlessly into software written for OpenAI backends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bypassing Dropdowns:&lt;/strong&gt; Choosing "OpenAI Compatible" instructs RooCode to treat the &lt;strong&gt;Model&lt;/strong&gt; box as a free-form text input rather than a strict, predefined dropdown menu, preventing the extension from stripping out unlisted models.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native Tool Calling:&lt;/strong&gt; RooCode requires full tool-calling support to write code and read files in your editor. Because &lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; supports native function calling out of the box via this bridge, RooCode's autonomous agent actions function normally.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pro-Tip:&lt;/strong&gt; If Google updates this model line in the future (e.g., to a newer point release), you only need to swap out the text string in the &lt;strong&gt;Model&lt;/strong&gt; field without changing any other parameters.&lt;/p&gt;

</description>
      <category>gemma</category>
      <category>kheai</category>
      <category>vscode</category>
      <category>vibecoding</category>
    </item>
    <item>
      <title>Why Build a Startup If Not for Money?</title>
      <dc:creator>Khe Ai</dc:creator>
      <pubDate>Tue, 02 Jun 2026 14:19:35 +0000</pubDate>
      <link>https://dev.to/kheai/why-build-a-startup-if-not-for-money-5cb6</link>
      <guid>https://dev.to/kheai/why-build-a-startup-if-not-for-money-5cb6</guid>
      <description>&lt;h3&gt;
  
  
  The Unspoken Playbook of the Sovereign Creator
&lt;/h3&gt;

&lt;p&gt;For decades, the dominant narrative around startups has been hyper-fixated on one metric: the exit. We are conditioned to view entrepreneurship through the lens of venture capital, hockey-stick growth charts, and generational wealth.&lt;/p&gt;

&lt;p&gt;But what happens when you remove financial gain from the primary equation? If you aren't doing it to buy a yacht or retire early, why on earth would you willingly subject yourself to the volatility, sleepless nights, and staggering failure rates of building something from scratch?&lt;/p&gt;

&lt;p&gt;When you strip away the financial incentive, you don't find passivity. Instead, you uncover the purest, most resilient forms of human drive. Here is what I have learned about what actually happens when you build a startup for everything &lt;em&gt;except&lt;/em&gt; the money—and why it might just be the ultimate way to live.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Reality Check: The Luxury of "Not Caring" About Capital
&lt;/h2&gt;

&lt;p&gt;Let’s be brutally honest and set a skeptical anchor right out of the gate: &lt;strong&gt;building a startup without prioritizing money is an act of immense privilege.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are struggling to pay rent or feed your family, the profit motive isn't just healthy; it is mandatory. But once you achieve baseline financial security—or if you choose to live a radically low-overhead lifestyle ("ramen profitable")—something fascinating happens to your decision-making matrix.&lt;/p&gt;

&lt;p&gt;When you optimize for revenue above all else, you are forced to make concessions. You build features you hate because a enterprise client demanded them. You chase trends because that’s where the VC funding is flowing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When money is no longer your master, &lt;strong&gt;compromise drops to zero.&lt;/strong&gt; You gain the rarest asset in modern business: absolute alignment between your values and your output.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. The Scratch You Cannot Stop Clawing (Obsessive Problem-Solving)
&lt;/h2&gt;

&lt;p&gt;Most people encounter a broken system, a terrible piece of software, or an inefficient workflow and think, &lt;em&gt;"Wow, that sucks,"&lt;/em&gt; before moving on with their day.&lt;/p&gt;

&lt;p&gt;But a specific subset of people suffer from what I call a "splinter in the mind." A broken reality agitates them. When you aren't building for money, you turn into a pure &lt;strong&gt;problem-solver&lt;/strong&gt;. You aren't scanning the market for "lucrative gaps"; you are dead-set on fixing a specific piece of the universe that is currently broken.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Shift in Focus
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Venture-Backed Mindset:&lt;/strong&gt; "Is the Total Addressable Market (TAM) big enough to justify an IPO?"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Sovereign Mindset:&lt;/strong&gt; "Does this solution need to exist in the world? Will it fundamentally improve the day-to-day existence of the people who use it?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This obsession creates a massive competitive advantage. When a profit-driven founder hits a wall where the financial ROI turns negative, they pivot or quit. When &lt;em&gt;you&lt;/em&gt; hit that same wall, you keep digging because your return on investment isn't measured in dollars—it’s measured in the eradication of the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The Hacker-Artist Paradigm: Pure Creation as an Antidote to Existential Dread
&lt;/h2&gt;

&lt;p&gt;There is a distinct joy in writing a clean line of code, designing an intuitive user interface, or crafting a seamless user experience. It is the joy of the artisan.&lt;/p&gt;

&lt;p&gt;Somewhere along the line, the tech world forgot that software engineering and company building are deeply creative acts. They are modern forms of art.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[The Industrial Loop]  → Produce for Consumption → Optimize for Scale  → Erase the Artisan&lt;/li&gt;
&lt;li&gt;[The Sovereign Loop]   → Build for the Sake of It → Optimize for Beauty → Preserves the Soul&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you build without the sole goal of monetization, you treat your startup like a canvas. You build things simply because they are beautiful, elegant, or intellectually stimulating. This is the ethos that built the early open-source movement and the early internet. It’s the desire to say, &lt;em&gt;"I was here, and I shaped this small corner of reality according to my own aesthetic."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The Autonomy Premium: Buying Back Your Sovereignty
&lt;/h2&gt;

&lt;p&gt;Corporate life is an exercise in managed compromise. You trade your time and your creative control for predictable compensation.&lt;/p&gt;

&lt;p&gt;For many of us, the true alternative to a startup isn't wealth—it’s &lt;strong&gt;sovereignty&lt;/strong&gt;. Building a project outside the traditional corporate matrix allows you to establish a micro-ecosystem that answers to no one but you and your users.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No arbitrary KPIs:&lt;/strong&gt; You don't have to hit fake metrics to please a board of directors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No political theater:&lt;/strong&gt; You don't waste 40% of your energy managing upwards or dealing with bureaucratic red tape.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Radical collaboration:&lt;/strong&gt; You choose exactly who you work with, ensuring that every teammate or user shares your specific wavelength.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You aren't trying to build an empire; you are trying to build a fortress that protects your personal freedom and intellectual peace.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Turning Life into a High-Fidelity Simulator
&lt;/h2&gt;

&lt;p&gt;Let’s face a hard truth: comfort breeds stagnation. If you don't need money, the easiest thing to do is sit back, consume content, and let your brain atrophy in a state of passive leisure.&lt;/p&gt;

&lt;p&gt;But passive leisure is a psychological trap that frequently leads to existential dread. Human beings are evolutionary engines designed to overcome friction.&lt;/p&gt;

&lt;p&gt;A startup is the ultimate high-fidelity simulator for personal growth. It tests every single dimension of your capability:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Intellectual:&lt;/strong&gt; You must master copywriting, system architecture, psychology, and legal frameworks simultaneously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emotional:&lt;/strong&gt; You have to deal with public criticism, bugs that break your system at 2:00 AM, and the vulnerability of putting your work out into the world.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Philosophical:&lt;/strong&gt; It forces you to constantly answer the question: &lt;em&gt;What is actually worth my limited time on this planet?&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By treating entrepreneurship as an elite sport rather than a financial transaction, the startup becomes a forcing function to turn you into the sharpest, most resilient version of yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary: The Post-Financial Playbook
&lt;/h2&gt;

&lt;p&gt;If someone asks you why you are pouring your life blood into a project that might never make you rich, show them this framework.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;The Conventional Startup&lt;/th&gt;
&lt;th&gt;The Sovereign Project&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary Metric&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Valuation &amp;amp; MRR (Monthly Recurring Revenue)&lt;/td&gt;
&lt;td&gt;Autonomy &amp;amp; Utility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scale Strategy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hyper-growth, often unsustainable&lt;/td&gt;
&lt;td&gt;Sustainable, often "One-Man" or micro-team&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Success State&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An acquisition or IPO&lt;/td&gt;
&lt;td&gt;An evergreen tool that runs flawlessly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Relationship to Users&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Monetizable data or traffic units&lt;/td&gt;
&lt;td&gt;A community of like-minded peers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Building without chasing money isn't aimless hobbyism. It is a highly disciplined, deeply intentional way to reclaim your time, express your creativity, and solve real-world problems on your own terms.&lt;/p&gt;

&lt;p&gt;Stop asking if it scales. Stop asking how it monetizes. &lt;strong&gt;Just build things that should exist.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>kheai</category>
      <category>startup</category>
      <category>sideprojects</category>
      <category>career</category>
    </item>
    <item>
      <title>Building a Decentralized Content Pipeline with Nostr &amp; Astro</title>
      <dc:creator>Khe Ai</dc:creator>
      <pubDate>Tue, 02 Jun 2026 07:36:04 +0000</pubDate>
      <link>https://dev.to/kheai/building-a-decentralized-content-pipeline-with-nostr-astro-5341</link>
      <guid>https://dev.to/kheai/building-a-decentralized-content-pipeline-with-nostr-astro-5341</guid>
      <description>&lt;p&gt;I recently deployed my fully decentralized content pipeline to &lt;a href="https://www.kheai.com" rel="noopener noreferrer"&gt;kheai.com&lt;/a&gt; (you can check out the source code at &lt;code&gt;github.com/kafechew/nostr-seo&lt;/code&gt;). After rigorously testing the architecture, I wanted to document exactly how this system works. We are not just building a blog; we are engineering an evergreen, censorship-resistant Web3-to-Web2 bridge.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kafechew" rel="noopener noreferrer"&gt;
        kafechew
      &lt;/a&gt; / &lt;a href="https://github.com/kafechew/nostr-seo" rel="noopener noreferrer"&gt;
        nostr-seo
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;⚡ Nostr-SEO: The Decentralized Content Bridge&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://www.kheai.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/23063cd2ddafe24ac99d461367aabbbacc0b5547ffff19110e6ac43d82d8fa46/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6976655f44656d6f2d6b686561692e636f6d2d3030433742373f7374796c653d666f722d7468652d6261646765" alt="Live Demo"&gt;&lt;/a&gt;
&lt;a href="https://astro.build/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/aee2410383a0c5c49033b8e1472bf7f9c9844cf9cc84a6170d0f0ba6efe72c20/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4275696c745f776974682d417374726f2d4646354430313f7374796c653d666f722d7468652d6261646765266c6f676f3d617374726f" alt="Built with Astro"&gt;&lt;/a&gt;
&lt;a href="https://nostr.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e45d8d3bf93c7e82f122d54edea8bf803b56fb349c40aed593b0c8f6781448a6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506f77657265645f62792d4e6f7374722d3832343146383f7374796c653d666f722d7468652d6261646765" alt="Powered by Nostr"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nostr-SEO&lt;/strong&gt; is a high-performance, SEO-first bridge that transforms decentralized Nostr Long-form content (&lt;strong&gt;Kind 30023&lt;/strong&gt;) into a lightning-fast, search-engine-optimized website.&lt;/p&gt;
&lt;p&gt;Built on top of the refined &lt;a href="https://github.com/satnaing/astro-paper" rel="noopener noreferrer"&gt;Astro-Paper&lt;/a&gt; template, this project allows creators to use Nostr as a decentralized CMS while maintaining total ownership of their web presence and search engine rankings.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📖 The Problem &amp;amp; Solution&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;The Problem&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;Decentralized protocols like Nostr are amazing for censorship resistance, but their content is often "invisible" to traditional search engines. If you publish only on relays, you lose the benefits of &lt;strong&gt;SEO (Search Engine Optimization)&lt;/strong&gt; and &lt;strong&gt;AEO (Answer Engine Optimization)&lt;/strong&gt; for AI agents like Perplexity and ChatGPT.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;The Solution&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;nostr-seo&lt;/code&gt; acts as a &lt;strong&gt;Static Site Generator (SSG) for the Nostr protocol&lt;/strong&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fetch:&lt;/strong&gt; It pulls your articles from decentralized relays at build-time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Process:&lt;/strong&gt; It cleans the Markdown, renders complex Math (LaTeX) and Diagrams (Mermaid).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy:&lt;/strong&gt; It…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kafechew/nostr-seo" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;In this tutorial, you will build an automated pipeline that fetches your long-form articles from decentralized Nostr clients (like Yakihonne or Primal), converts them into a blazing-fast static website using Astro, and hosts it for free on Vercel.&lt;/p&gt;

&lt;p&gt;Zero prior Astro experience is required. If you follow these steps, you will go from an empty folder to a live, SEO-optimized prototype.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture Vision
&lt;/h2&gt;

&lt;p&gt;Before writing code, you must understand the data flow. We are shifting from a "push" model (saving files to a server) to a "pull" model (compiling decentralized data at build time).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph TD
    A[Author on Yakihonne/Primal] --&amp;gt;|Publishes Kind 30023| B(Nostr Relays)
    C[GitHub Actions Cron] --&amp;gt;|Triggers Build every 6h| D(Vercel Edge Network)
    D --&amp;gt;|Fetches Data| B
    D --&amp;gt;|Compiles HTML/CSS| E[Your Live Website]
    E --&amp;gt; F[Human Readers]
    E --&amp;gt; G[AI Agents via llm.txt]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Component&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Tool&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Network&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Nostr Protocol&lt;/td&gt;
&lt;td&gt;Decentralized content storage and syndication.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Framework&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Astro (AstroPaper)&lt;/td&gt;
&lt;td&gt;High-speed static site generation and routing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Processor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Unified Ecosystem&lt;/td&gt;
&lt;td&gt;Parsing Markdown, KaTeX (math), and Mermaid (diagrams).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hosting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;td&gt;Edge delivery and automated webhooks.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Phase 0: The Digital Workbench
&lt;/h2&gt;

&lt;p&gt;You need a few standard tools installed before we begin.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download and install the &lt;strong&gt;LTS (Long Term Support)&lt;/strong&gt; version of Node.js from &lt;code&gt;nodejs.org&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Install Git from &lt;code&gt;git-scm.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Download Visual Studio Code, the industry-standard code editor.&lt;/li&gt;
&lt;li&gt;Create free accounts on GitHub and Vercel.&lt;/li&gt;
&lt;li&gt;Convert your Nostr &lt;code&gt;npub&lt;/code&gt; to a Hexadecimal key using a tool like &lt;code&gt;damus.io/key&lt;/code&gt;. Keep this Hex key safe; our code needs it to identify you on the network.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Phase 1: Local Setup &amp;amp; Installation
&lt;/h2&gt;

&lt;p&gt;Open your terminal. We will use the AstroPaper template as our foundation.&lt;/p&gt;

&lt;p&gt;Run the following command to download the template into a new folder named &lt;code&gt;nostr-seo&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create astro@latest &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--template&lt;/span&gt; satnaing/astro-paper nostr-seo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate into your new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;nostr-seo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we must install our communication tools (NDK for Nostr) and our processing engines (Unified for Markdown/Math). Run this command exactly as written:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @nostr-dev-kit/ndk ws nostr-tools remark-math rehype-katex rehype-stringify remark-rehype remark-parse unified &lt;span class="nt"&gt;--legacy-peer-deps&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: The &lt;code&gt;--legacy-peer-deps&lt;/code&gt; flag prevents npm from crashing if the Astro template's default formatting tools have strict version conflicts with our new parser.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The MacOS/Linux WebAssembly Patch
&lt;/h3&gt;

&lt;p&gt;If you are on an older OS, the build engine (&lt;code&gt;esbuild&lt;/code&gt;) might fail. Open your &lt;code&gt;package.json&lt;/code&gt; file and append these properties to force Node.js to bypass your core OS framework and use WebAssembly instead:&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;"devDependencies"&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;"esbuild-wasm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.28.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;"overrides"&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;"esbuild"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm:esbuild-wasm@0.28.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="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;Open the project in your editor by typing &lt;code&gt;code .&lt;/code&gt; in your terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 2: Core Engineering &amp;amp; Data Pipelines
&lt;/h2&gt;

&lt;p&gt;Because we are fetching posts from Nostr relays rather than local &lt;code&gt;.md&lt;/code&gt; files, we must create a custom processing pipeline to handle rich text, math equations, and metadata.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: The Markdown Processor
&lt;/h3&gt;

&lt;p&gt;Create a new file at &lt;code&gt;src/utils/parseMarkdown.ts&lt;/code&gt;. This utility converts raw Nostr strings into safe, styled HTML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;unified&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unified&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;remarkParse&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remark-parse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;remarkMath&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remark-math&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;remarkRehype&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remark-rehype&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;rehypeKatex&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rehype-katex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;rehypeStringify&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rehype-stringify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseNostrMarkdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;unified&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;remarkParse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;remarkMath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;remarkRehype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rehypeKatex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rehypeStringify&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&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;
  
  
  Step 2: The Event Formatter
&lt;/h3&gt;

&lt;p&gt;Create a new file at &lt;code&gt;src/utils/formatNostrEvent.ts&lt;/code&gt;. This extracts SEO descriptions and generates proper &lt;code&gt;naddr&lt;/code&gt; links for cross-platform Web3 sharing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;nip19&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nostr-tools&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;formatNostrEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;findTag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)?.[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;findTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;summary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fallbackDesc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/!&lt;/span&gt;&lt;span class="se"&gt;\[&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;?\]\(&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;?\)&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&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="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\[(&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;?)\]\(&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;?\)&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$1&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="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;__|&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;*#`&lt;/span&gt;&lt;span class="se"&gt;\[\]&lt;/span&gt;&lt;span class="sr"&gt;()&lt;/span&gt;&lt;span class="se"&gt;\-&lt;/span&gt;&lt;span class="sr"&gt;+!=&lt;/span&gt;&lt;span class="se"&gt;])&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&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="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dTag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;findTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;naddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;naddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nip19&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;naddrEncode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30023&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;pubkey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pubkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dTag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Naddr error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;naddr&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;findTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Untitled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;fallbackDesc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;pubDatetime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;created_at&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;modDatetime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;findTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;author&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nostr User&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;t&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="na"&gt;ogImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;findTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;naddr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;naddr&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;h2&gt;
  
  
  Phase 3: Building the Interface
&lt;/h2&gt;

&lt;p&gt;We will hijack AstroPaper's default routing to dynamically pull your Kind 30023 events at build time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: The Homepage (&lt;code&gt;index.astro&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Navigate to &lt;code&gt;src/pages/index.astro&lt;/code&gt;. Delete everything and paste the code below. &lt;strong&gt;Replace the Hex string with your own public key.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
import Layout from "@/layouts/Layout.astro";
import Header from "@/components/Header.astro";
import Footer from "@/components/Footer.astro";
import NDK, { type NDKEvent } from "@nostr-dev-kit/ndk";
import 'ws'; 

const ndk = new NDK({ 
  explicitRelayUrls: [
    "wss://relay.damus.io", 
    "wss://nos.lol",
    "wss://relay.primal.net"
  ] 
});

try {
  await ndk.connect(3000); 
} catch (err) {
  console.error("Nostr Connection failed:", err);
}

// REMEMBER TO INSERT YOUR HEX KEY BELOW
const filter = { 
  kinds: [30023], 
  authors: ["YOUR_HEX_PUBLIC_KEY_HERE"]
};

let events: Set&amp;lt;NDKEvent&amp;gt; = new Set();

try {
  const fetchPromise = ndk.fetchEvents(filter, { closeOnEose: true });
  const timeoutPromise = new Promise&amp;lt;Set&amp;lt;NDKEvent&amp;gt;&amp;gt;((resolve) =&amp;gt; {
    setTimeout(() =&amp;gt; resolve(new Set()), 4000);
  });

  events = await Promise.race([fetchPromise, timeoutPromise]);
} catch (err) {
  console.error("Fetch error:", err);
}

const posts = Array.from(events)
  .filter((e): e is NDKEvent &amp;amp; { created_at: number } =&amp;gt; e.created_at !== undefined)
  .sort((a, b) =&amp;gt; b.created_at - a.created_at)
  .map(e =&amp;gt; {
    const cleanContent = e.content.replace(/[#*`_~\[\]\(\)-]/g, "").replace(/\s+/g, " ").trim();
    return {
      id: e.id,
      title: e.tags.find((t: string[]) =&amp;gt; t[0] === 'title')?.[1] || "Untitled Post",
      summary: e.tags.find((t: string[]) =&amp;gt; t[0] === 'summary')?.[1] || (cleanContent.substring(0, 120) + "..."),
      date: new Date(e.created_at * 1000).toLocaleDateString('en-US', {
        year: 'numeric', month: 'long', day: 'numeric'
      })
    };
  });
---

&amp;lt;Layout title="My Decentralized Mind-Dump"&amp;gt;
  &amp;lt;Header /&amp;gt;
  &amp;lt;main id="main-content" class="app-layout"&amp;gt;
    &amp;lt;section id="hero" class="border-border border-b pt-8 pb-6"&amp;gt;
      &amp;lt;h1 class="my-4 inline-block text-4xl font-bold sm:my-8 sm:text-5xl"&amp;gt;My Nostr Mind-Dump&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;Pulled dynamically from the Nostr protocol at build time. Write on Web3, read everywhere.&amp;lt;/p&amp;gt;
    &amp;lt;/section&amp;gt;

    &amp;lt;section id="recent-posts" class="pt-12 pb-6"&amp;gt;
      &amp;lt;h2 class="text-2xl font-semibold tracking-wide mb-6"&amp;gt;Recent Notes&amp;lt;/h2&amp;gt;
      &amp;lt;ul&amp;gt;
        {posts.map(post =&amp;gt; (
          &amp;lt;li class="my-6"&amp;gt;
            &amp;lt;a href={`/nostr/${post.id}`} class="inline-block text-xl font-bold text-skin-accent decoration-dashed underline-offset-4 hover:underline"&amp;gt;
              {post.title}
            &amp;lt;/a&amp;gt;
            &amp;lt;div class="text-sm opacity-80 mt-1"&amp;gt;{post.date}&amp;lt;/div&amp;gt;
            &amp;lt;p class="mt-2 line-clamp-3"&amp;gt;{post.summary}&amp;lt;/p&amp;gt;
          &amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/section&amp;gt;
  &amp;lt;/main&amp;gt;
  &amp;lt;Footer /&amp;gt;
&amp;lt;/Layout&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: The Article Reader Route
&lt;/h3&gt;

&lt;p&gt;Create a new folder named &lt;code&gt;nostr&lt;/code&gt; inside &lt;code&gt;src/pages/&lt;/code&gt;. Inside that folder, create &lt;code&gt;[id].astro&lt;/code&gt;. This generates dynamic paths for every article.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
import Layout from "@/layouts/Layout.astro";
import Header from "@/components/Header.astro";
import Footer from "@/components/Footer.astro";
import NDK, { type NDKEvent } from "@nostr-dev-kit/ndk";
import 'ws';
import { parseNostrMarkdown } from "@/utils/parseMarkdown";
import { formatNostrEvent } from "@/utils/formatNostrEvent";

export async function getStaticPaths() {
  const ndk = new NDK({ explicitRelayUrls: ["wss://relay.damus.io", "wss://nos.lol"] });
  await ndk.connect(3000);

  let events: Set&amp;lt;NDKEvent&amp;gt; = new Set();

  // REMEMBER TO INSERT YOUR HEX KEY BELOW
  const filter = { kinds: [30023], authors: ["YOUR_HEX_PUBLIC_KEY_HERE"] };
  const fetchPromise = ndk.fetchEvents(filter, { closeOnEose: true });
  const timeoutPromise = new Promise&amp;lt;Set&amp;lt;NDKEvent&amp;gt;&amp;gt;((resolve) =&amp;gt; setTimeout(() =&amp;gt; resolve(new Set()), 4000));

  events = await Promise.race([fetchPromise, timeoutPromise]);

  return Array.from(events)
    .filter((e): e is NDKEvent &amp;amp; { created_at: number } =&amp;gt; e.created_at !== undefined)
    .map(e =&amp;gt; ({
      params: { id: e.id },
      props: { event: e }
    }));
}

interface Props { event: NDKEvent; }
const { event } = Astro.props;
const post = formatNostrEvent(event);
const htmlContent = await parseNostrMarkdown(post.content);
---

&amp;lt;Layout title={post.title}&amp;gt;
  &amp;lt;link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css" crossorigin="anonymous" /&amp;gt;
  &amp;lt;Header /&amp;gt;

  &amp;lt;main id="main-content" class="mx-auto w-full max-w-3xl px-4 pb-12 mt-8"&amp;gt;
    &amp;lt;button class="focus-outline mb-6 flex hover:opacity-75" onclick="history.back()"&amp;gt;
      &amp;lt;span&amp;gt;← Go back&amp;lt;/span&amp;gt;
    &amp;lt;/button&amp;gt;
    &amp;lt;h1 class="text-3xl font-bold text-skin-accent"&amp;gt;{post.title}&amp;lt;/h1&amp;gt;

    {post.naddr &amp;amp;&amp;amp; (
      &amp;lt;div class="mt-6 flex flex-wrap items-center gap-3 text-sm bg-skin-card/10 p-4 rounded-lg border border-skin-line/50"&amp;gt;
        &amp;lt;span class="font-bold"&amp;gt;⚡ Nostr:&amp;lt;/span&amp;gt;
        &amp;lt;a href={`nostr:${post.naddr}`} class="text-skin-accent hover:underline"&amp;gt;Open in App&amp;lt;/a&amp;gt;
        &amp;lt;a href={`https://yakihonne.com/article/${post.naddr}`} target="_blank" class="hover:text-skin-accent opacity-80"&amp;gt;Yakihonne&amp;lt;/a&amp;gt;
      &amp;lt;/div&amp;gt;
    )}

    &amp;lt;article class="prose max-w-none prose-img:border-0 mt-8" set:html={htmlContent} /&amp;gt;
  &amp;lt;/main&amp;gt;
  &amp;lt;Footer /&amp;gt;
&amp;lt;/Layout&amp;gt;

&amp;lt;script&amp;gt;
  const renderMermaid = async () =&amp;gt; {
    const codeBlocks = document.querySelectorAll("pre code.language-mermaid");
    if (codeBlocks.length === 0) return;
    const { default: mermaid } = await import("https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs");
    mermaid.initialize({ startOnLoad: false, theme: "dark" });

    for (const element of codeBlocks) {
      const id = `mermaid-${Math.random().toString(36).substr(2, 9)}`;
      const { svg } = await mermaid.render(id, element.textContent || "");
      const wrapper = document.createElement('div');
      wrapper.className = 'mermaid-container my-8 flex justify-center overflow-x-auto';
      wrapper.innerHTML = svg;
      element.parentElement?.replaceWith(wrapper);
    }
  };
  renderMermaid();
  document.addEventListener("astro:after-swap", renderMermaid);
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Global Styling and Contrast Fixes
&lt;/h3&gt;

&lt;p&gt;Add these definitions to &lt;code&gt;src/styles/global.css&lt;/code&gt; to fix dark mode contrast, ensure math blocks scroll gracefully on mobile, and apply proper borders to user-uploaded images.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Improve contrast for Dark Mode */&lt;/span&gt;
&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"dark"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.prose&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--tw-prose-body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;"colors.slate.200"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--tw-prose-headings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;"colors.white"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--tw-prose-bold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;"colors.white"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* KaTeX Math Styling */&lt;/span&gt;
&lt;span class="nc"&gt;.katex-display&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;my-8&lt;/span&gt; &lt;span class="err"&gt;overflow-x-auto&lt;/span&gt; &lt;span class="err"&gt;py-4&lt;/span&gt; &lt;span class="err"&gt;px-2&lt;/span&gt; &lt;span class="err"&gt;rounded-lg;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.03&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.katex&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;white-space&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;nowrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Nostr Image Attachments */&lt;/span&gt;
&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;rounded-xl&lt;/span&gt; &lt;span class="err"&gt;border&lt;/span&gt; &lt;span class="err"&gt;shadow-md&lt;/span&gt; &lt;span class="err"&gt;mx-auto&lt;/span&gt; &lt;span class="err"&gt;my-8;&lt;/span&gt;
  &lt;span class="nl"&gt;border-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-line&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;Start your local server by running &lt;code&gt;npm run dev&lt;/code&gt; and opening &lt;code&gt;http://localhost:4321&lt;/code&gt;. Your site should now dynamically render your Nostr notes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 4: AI-Native SEO (&lt;code&gt;llm.txt&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;As AI agents like Perplexity and SearchGPT replace traditional search engines, we must provide a semantic layer.&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;llm.txt&lt;/code&gt; inside your &lt;code&gt;public/&lt;/code&gt; folder. Write a direct, markdown-formatted summary of your site's core philosophy and architecture. When an AI scrapes &lt;code&gt;yourwebsite.com/llm.txt&lt;/code&gt;, it immediately contextualizes your niche with zero token waste.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 5: Deployment &amp;amp; The Zero-Maintenance Pipeline
&lt;/h2&gt;

&lt;p&gt;It is time to put your site on the public internet and automate the build process.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push your code to a new public GitHub repository.&lt;/li&gt;
&lt;li&gt;Log into Vercel, click &lt;strong&gt;Add New Project&lt;/strong&gt;, import your repository, and click &lt;strong&gt;Deploy&lt;/strong&gt;. Vercel will grant you a live URL.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Automation Webhook
&lt;/h3&gt;

&lt;p&gt;Right now, your site is static. If you publish a new article on Nostr, your site won't update until Vercel builds again.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In your Vercel Dashboard, navigate to &lt;strong&gt;Settings -&amp;gt; Git -&amp;gt; Deploy Hooks&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Create a hook named &lt;code&gt;Nostr-Sync&lt;/code&gt; on the &lt;code&gt;main&lt;/code&gt; branch and copy the generated URL.&lt;/li&gt;
&lt;li&gt;In your GitHub repository, go to the &lt;strong&gt;Actions&lt;/strong&gt; tab and create a new workflow named &lt;code&gt;nostr-sync.yml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Paste the following configuration, replacing the URL with your unique Vercel hook:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Nostr Auto-Sync&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*/6&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Trigger Vercel Build&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;curl -X POST "https://api.vercel.com/v1/integrations/deploy/YOUR_UNIQUE_VERCEL_HOOK_URL"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Commit the changes.&lt;/p&gt;

&lt;p&gt;You have successfully engineered an evergreen architecture. You write natively on Nostr, retaining absolute ownership of your cryptographic keys. Every 6 hours, GitHub Actions silently signals Vercel. Vercel scrapes the relays, compiles your latest thoughts into high-speed HTML, and serves it globally. Write once, syndicate everywhere.&lt;/p&gt;

</description>
      <category>nostr</category>
      <category>kheai</category>
      <category>astro</category>
      <category>seo</category>
    </item>
    <item>
      <title>Zeroing Out the Bill: The Developer’s Practical Guide to Eliminating Google Cloud (GCP) Idle Costs</title>
      <dc:creator>Khe Ai</dc:creator>
      <pubDate>Tue, 02 Jun 2026 07:20:06 +0000</pubDate>
      <link>https://dev.to/kheai/zeroing-out-the-bill-the-developers-practical-guide-to-eliminating-google-cloud-gcp-idle-costs-34c3</link>
      <guid>https://dev.to/kheai/zeroing-out-the-bill-the-developers-practical-guide-to-eliminating-google-cloud-gcp-idle-costs-34c3</guid>
      <description>&lt;p&gt;It is a classic developer milestone: you finish a side project, proof-of-concept, or staging test, and you responsibly tear down your infrastructure. You scale your compute instances to zero, delete or pause your databases, and walk away believing your cloud spend has dropped to absolute zero.&lt;/p&gt;

&lt;p&gt;Then, the billing dashboard updates. You spot a persistent trickle of costs—fractions of a cent tracking a linear line upwards across your billing period. While the numbers seem trivial at a small scale (fractions of a cent tracking toward a dollar), these phantom charges represent a fundamental design mechanic in cloud systems: &lt;strong&gt;the hidden tax of at-rest storage&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Core Rule of Cloud Billing:&lt;/strong&gt; Compute is easily turned off, but data has gravity. If it occupies physical sectors on a disk in a cloud data center somewhere, Google will bill you for it—even if your applications are completely dark.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This guide details exactly why these costs happen, builds a framework for all potential dormant cloud costs you must guard against, and outlines automated strategies to achieve a true $0.00 infrastructure bill when your code is idle.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Anatomy of the Staging Bill
&lt;/h2&gt;

&lt;p&gt;When analyzing a low-cost, idle cloud project dashboard, expenditures typically pool into three specific storage-based categories after compute instances are scaled down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Artifact Registry:&lt;/strong&gt; Charges arise from hosting historical application build containers, package fragments, or deployment source artifacts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud SQL (Metadata/Storage Component):&lt;/strong&gt; Even if an instance is stopped or deleted, persistent disks, backups, and IP assignments can sustain unyielding baseline costs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Storage (GCS):&lt;/strong&gt; Acts as the underlying system storage bucket infrastructure where automated frameworks drop deployment bundles, pipeline states, and continuous integration caches.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Deep-Dive: Remediation &amp;amp; Automation Strategies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Artifact Registry: Purging Container Bloat
&lt;/h3&gt;

&lt;p&gt;Every single time a deployment pipeline runs (e.g., deploying code to Cloud Run), a baseline container image is generated and stored inside the Artifact Registry repository. Over weeks of iterations, these untagged historical layers build up significant digital debris.&lt;/p&gt;

&lt;h4&gt;
  
  
  🛠️ The Permanent Automated Fix
&lt;/h4&gt;

&lt;p&gt;Do not rely on manual cleanup. Set up a declarative &lt;strong&gt;Cleanup Policy&lt;/strong&gt; inside your repository:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Artifact Registry &amp;gt; Repositories&lt;/strong&gt; and select your deployment repository.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Edit Repository&lt;/strong&gt; and scroll down to the &lt;strong&gt;Cleanup policies&lt;/strong&gt; manager.&lt;/li&gt;
&lt;li&gt;Add a rule with the condition &lt;strong&gt;Tag State: Any Tag State&lt;/strong&gt; combined with an age threshold like &lt;code&gt;Older than: 7d&lt;/code&gt; (7 days).&lt;/li&gt;
&lt;li&gt;Change the evaluation enforcement action from &lt;em&gt;Dry Run&lt;/em&gt; to &lt;strong&gt;Delete artifacts&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Cloud Storage: Mitigating Automated Backend Artifacts
&lt;/h3&gt;

&lt;p&gt;Tools like Cloud Build naturally create cloud storage buckets (e.g., &lt;code&gt;staging.project-id.appspot.com&lt;/code&gt; or &lt;code&gt;project-id_cloudbuild&lt;/code&gt;) to compress and transport your code source before compiling it. These source zip files often remain forever unless lifecycle management intervenes.&lt;/p&gt;

&lt;p&gt;To eliminate these costs passively, implement Object Lifecycle Management rules on your buckets via the console or globally via the &lt;code&gt;gcloud&lt;/code&gt; CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"rule": [{"action": {"type": "Delete"}, "condition": {"age": 7}}]}'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; lifecycle.json
gcloud storage buckets update gs://YOUR_BUILDS_BUCKET &lt;span class="nt"&gt;--lifecycle-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lifecycle.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ &lt;strong&gt;Watch Out for the "Soft Delete" Catch:&lt;/strong&gt; Google Cloud includes a default &lt;strong&gt;Soft Delete Policy&lt;/strong&gt; on all new buckets. When an object lifecycle rule executes, or you manually delete a file, the object is placed in an invisible soft-deleted state for &lt;strong&gt;7 days&lt;/strong&gt; to allow recovery. During this window, you are still billed at regular storage rates! To achieve immediate bill reduction, click the bucket's &lt;strong&gt;Configuration&lt;/strong&gt; tab, locate the Soft Delete Policy, edit it, and set the duration value to &lt;code&gt;0 days&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Comprehensive Checklist: Every Potential Idle Cost in GCP
&lt;/h2&gt;

&lt;p&gt;To ensure your environment does not accumulate unexpected bills, use this definitive reference table outlining common services, their hidden idle costs, and exact mitigation vectors:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Service Category&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;What Charges You While Idle&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Estimated Unit Cost (US)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Mitigation Action&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloud Run / GCF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Minimum CPU Instances allocated to stay warm; CPU allocation set to "Always Allocated".&lt;/td&gt;
&lt;td&gt;~0.04 / vCPU-hour&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;min-instances&lt;/code&gt; to 0; switch CPU allocation to "Only during request processing".&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Artifact Registry&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Active container storage layer data at-rest.&lt;/td&gt;
&lt;td&gt;~0.10 per GB / month&lt;/td&gt;
&lt;td&gt;Apply automated Repository Cleanup Policies (Age &amp;lt; 7-14 days).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloud Storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Standard, Nearline, or Coldline storage data; Soft-deleted objects waiting out retention windows.&lt;/td&gt;
&lt;td&gt;~0.02 to 0.026 per GB / month (Standard)&lt;/td&gt;
&lt;td&gt;Set Object Lifecycle policies to auto-delete; modify Soft Delete retention to 0 days.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloud SQL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Persistent Disk space (SSD/HDD); Automated database backup snapshots; Retained Static IP configurations.&lt;/td&gt;
&lt;td&gt;~0.17 per GB/mo (SSD) ~0.01 to 0.025 per hour for IP&lt;/td&gt;
&lt;td&gt;Stopping instances halts CPU/RAM charges but &lt;strong&gt;keeps charging for disk/IPs&lt;/strong&gt;. Clone data, export to GCS, and delete the instance fully.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compute Engine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Unattached Persistent Disks (PDs); Orphaned Static External IP Addresses.&lt;/td&gt;
&lt;td&gt;~0.04 per GB/mo (Standard) ~0.01 / hour idle IP&lt;/td&gt;
&lt;td&gt;Go to Compute Engine &amp;gt; Disks and delete detached storage; Release unused static external IPs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VPC Networking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Forwarding rules (Load Balancers left running without active backends); NAT Gateways.&lt;/td&gt;
&lt;td&gt;~0.025+ per hour per rule / gateway&lt;/td&gt;
&lt;td&gt;Delete idle External HTTP(S) Load Balancers and Cloud NAT gateways when unneeded.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vertex AI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dormant custom notebooks (User-managed instances); Deployed endpoints hosting models.&lt;/td&gt;
&lt;td&gt;Varies by underlying Compute Engine sizing&lt;/td&gt;
&lt;td&gt;Stop Vertex Workbench notebooks when not coding; Undeploy models from active prediction endpoints.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Logging &amp;amp; Monitoring&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Log ingestion exceeding the free 50 GiB/month limit; Custom metric collection data.&lt;/td&gt;
&lt;td&gt;~0.50 per GiB ingested&lt;/td&gt;
&lt;td&gt;Set up log exclusion filters to drop high-volume stdout/stderr debug records.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  4. Summary Blueprint for Staging Environments
&lt;/h2&gt;

&lt;p&gt;To keep your non-production workloads under absolute financial control, embed the following hygiene habits into your architectural processes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure as Code (IaC):&lt;/strong&gt; Define environment testbeds completely in Terraform. Instead of spinning services down or pausing individual configurations, execute a wholesale &lt;code&gt;terraform destroy&lt;/code&gt; when the sprint or research spike ends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Budget Alerts with Pub/Sub:&lt;/strong&gt; Do not rely on looking at the console. Create a hyper-sensitive budget alert (e.g., at $1.00) linked to a Cloud Function that automatically initiates teardowns if thresholds are breached.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tagging and Labels:&lt;/strong&gt; Label everything with &lt;code&gt;env: staging&lt;/code&gt; or &lt;code&gt;owner: developer_name&lt;/code&gt;. This lets you sort your billing console instantly by labels to identify which resource group is generating background noise.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By shifting from manual infrastructure adjustments to structured automated lifecycles, you turn cloud cost optimization into an immutable background process—leaving your dashboard clean, predictable, and flat.&lt;/p&gt;

</description>
      <category>gcp</category>
      <category>kheai</category>
      <category>infrastructure</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Barbell Founder: Why I Chose to be a Part-timer to Protect My Startup</title>
      <dc:creator>Khe Ai</dc:creator>
      <pubDate>Sun, 10 May 2026 14:50:07 +0000</pubDate>
      <link>https://dev.to/kheai/the-barbell-founder-why-i-chose-to-be-a-part-timer-to-protect-my-startup-31pb</link>
      <guid>https://dev.to/kheai/the-barbell-founder-why-i-chose-to-be-a-part-timer-to-protect-my-startup-31pb</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Stop optimizing for nominal wages. Start optimizing for cognitive surplus and time sovereignty.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the modern startup ecosystem, there is a piece of conventional wisdom that acts as a silent killer: &lt;em&gt;“Get a high-paying, stable corporate job to fund your dream.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On paper, it sounds responsible. In reality, it is a trap. For a founder—especially a technical one—a high-status full-time role is often a "gold-plated cage" that drains your energy, steals your intellectual property, and ensures you never have the "escape velocity" needed to launch.&lt;/p&gt;

&lt;p&gt;I have abandoned that path. Instead, I have adopted a radical decoupling of &lt;strong&gt;Survival&lt;/strong&gt; from &lt;strong&gt;Self-Actualization&lt;/strong&gt;. I call it the &lt;strong&gt;Low-Entropy Employment Model&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/protocol/260510-barbell-founder_p14yTs7I4.png" rel="noopener noreferrer"&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%2F1org8rvfvvyi2kaabq3f.png" alt="The Barbell Founder: Why I Chose an RM 8.72 Walking Job to Protect My Startup" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Strategy: Nassim Taleb’s Barbell
&lt;/h2&gt;

&lt;p&gt;In finance, the Barbell Strategy involves avoiding the "middle ground." You place 90% of your resources in hyper-safe, boring assets to guarantee survival, and 10% in highly aggressive, speculative bets for massive upside.&lt;/p&gt;

&lt;p&gt;I have applied this to my life:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Safety (90%):&lt;/strong&gt; A "mindless," part-time, or contract job that is walkable and stress-free. It provides the &lt;strong&gt;Minimum Viable Income&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Aggression (10%):&lt;/strong&gt; My startup. This is where 100% of my ambition, creativity, and aggression are focused.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most people get stuck in the middle—a moderately stressful, moderately paying job that pays just enough to stay comfortable, but drains just enough energy to stay stagnant.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Biology: Cognitive Surplus vs. Ego Depletion
&lt;/h2&gt;

&lt;p&gt;Why do I prioritize "mindless" work? Because of a psychological reality called &lt;strong&gt;Ego Depletion&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The human brain has a finite daily reservoir of willpower and decision-making capacity. If your day job requires you to solve complex algorithmic problems, navigate toxic office politics, or manage high-stakes client crises, your prefrontal cortex is chemically exhausted by 5:00 PM.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Founder’s Axiom:&lt;/strong&gt; Free time is useless if you have no cognitive energy left to spend.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By choosing a low-entropy job, I arrive at my "startup hours" with my nervous system intact. I am not "recovering" from my day job; I am starting my real day with a full battery.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The Math: The "True Hourly Rate" Illusion
&lt;/h2&gt;

&lt;p&gt;Let’s use a skeptical, research-based simulation to debunk the "higher pay" myth. Consider two options for a 5-hour part-time shift (20 days/month):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Option A:&lt;/strong&gt; A local job within walking distance. Pay: &lt;strong&gt;RM 8.72/hr&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Option B:&lt;/strong&gt; A "better" job requiring a commute (MRT/LRT). Pay: &lt;strong&gt;RM 11.00/hr&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Society says take Option B. The math says otherwise when we calculate the &lt;strong&gt;Total Cost of Employment (TCE)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;$$True\ Hourly\ Rate = \frac{Total\ Daily\ Income}{Hours\ Worked + Commute\ Time}$$&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Metric&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Option A (Local)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Option B (Commute)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gross Daily Income&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;RM 43.60&lt;/td&gt;
&lt;td&gt;RM 55.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Time Invested&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5.5 Hours (0.5h walk)&lt;/td&gt;
&lt;td&gt;7.5 Hours (2.5h transit)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;True Hourly Rate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RM 7.92 / hr&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RM 7.33 / hr&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The Verdict:&lt;/strong&gt; Option B is a net loss. Not only is the true rate lower, but the &lt;strong&gt;Opportunity Cost&lt;/strong&gt; is 40 hours of lost time per month. Those 40 hours could be used to write 3 government grants, pitch 50 investors, or build a core product feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The Invisible Chains: The Risk of Full-Time
&lt;/h2&gt;

&lt;p&gt;For a programmer or technical founder, a salaried full-time role is strategically dangerous.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Intellectual Property (IP) Trap
&lt;/h3&gt;

&lt;p&gt;Standard full-time contracts often include "Assignment of Inventions" clauses. Legally, any code you write—even on your own laptop at 2:00 AM—can be claimed by your employer if it’s even tangentially related to their field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution:&lt;/strong&gt; Freelance or part-time contracts are "cleaner." They define a narrow scope of work, leaving your "after-hours" IP safely in your hands.&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Identity Tax"
&lt;/h3&gt;

&lt;p&gt;Corporate culture demands emotional "alignment." They want you to care about &lt;em&gt;their&lt;/em&gt; vision. This creates an &lt;strong&gt;Emotional Sunk Cost&lt;/strong&gt;. You start optimizing for a promotion you don't actually want, which tethers your self-worth to a hierarchy you don't own.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Non-Compete Chokehold
&lt;/h3&gt;

&lt;p&gt;Full-time roles often come with non-compete clauses that can legally block you from launching a startup in a similar industry for years. mercenary, part-time roles rarely carry this legal weight.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. The Execution
&lt;/h2&gt;

&lt;p&gt;This strategy is not a "slack-off" plan. It is an &lt;strong&gt;optimization plan&lt;/strong&gt;. To make it work, you must adhere to three strict rules:&lt;/p&gt;

&lt;h3&gt;
  
  
  I. Minimalist Consumption
&lt;/h3&gt;

&lt;p&gt;You cannot live a high-status lifestyle on a low-entropy income. You must be a &lt;strong&gt;Minimalist in Consumption&lt;/strong&gt; to remain a &lt;strong&gt;Maximalist in Production&lt;/strong&gt;. Every RM saved is a second of freedom bought.&lt;/p&gt;

&lt;h3&gt;
  
  
  II. The Health &amp;amp; Legal Buffer
&lt;/h3&gt;

&lt;p&gt;Since you are forgoing corporate benefits, you must be disciplined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Insurance:&lt;/strong&gt; Use a portion of your income to secure your own medical and life insurance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contract Review:&lt;/strong&gt; Never sign a part-time contract without checking for IP-grabbing clauses.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  III. The Discipline Filter
&lt;/h3&gt;

&lt;p&gt;If you take an "easy" job but spend your reclaimed 40 hours on Netflix or gaming, you aren't a Barbell Founder—you are just underemployed. This strategy only works if you go to "war" for your startup the moment you clock out of your survival job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Time Sovereignty is the Ultimate Weapon
&lt;/h2&gt;

&lt;p&gt;In the startup game, the person who can stay in the arena the longest wins. By lowering your burn rate and protecting your cognitive energy, you become incredibly difficult to kill.&lt;/p&gt;

&lt;p&gt;Stop optimizing for a job title. Start optimizing for &lt;strong&gt;Time Sovereignty&lt;/strong&gt;. Your startup deserves your best brain—don't sell it to the highest bidder for a few extra Ringgit and a long commute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is your "True Hourly Rate" today? Is it time to quit the "good" job for the right one?&lt;/strong&gt; &lt;/p&gt;

</description>
      <category>startup</category>
      <category>career</category>
      <category>kheai</category>
      <category>programmers</category>
    </item>
    <item>
      <title>Building an AI-Powered ERP System with Gemma 26B MoE, .NET 8, Python &amp; React</title>
      <dc:creator>Khe Ai</dc:creator>
      <pubDate>Sat, 09 May 2026 06:25:26 +0000</pubDate>
      <link>https://dev.to/kheai/building-an-ai-powered-erp-system-with-gemma-26b-moe-net-8-python-react-3noh</link>
      <guid>https://dev.to/kheai/building-an-ai-powered-erp-system-with-gemma-26b-moe-net-8-python-react-3noh</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-gemma-2026-05-06"&gt;Gemma 4 Challenge: Write About Gemma 4&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Building an industrial-grade SaaS from scratch can feel daunting. As a software engineer, I’ve found that the secret to not getting overwhelmed is architecture. When you break down complex monolithic systems into manageable, robust microservices, that’s where the real fun begins.&lt;/p&gt;

&lt;p&gt;Recently, I built &lt;strong&gt;Y&amp;amp;Y App (yny)&lt;/strong&gt;—a comprehensive, microservices-based ERP-lite system. But it doesn't just manage inventory; it integrates a specialized AI Domain-Expert Agent that can read technical manuals and troubleshoot industrial equipment in real-time.&lt;/p&gt;

&lt;p&gt;In this masterclass, I am going to walk you through exactly how I built it, step-by-step. By the end of this guide, you will transition from a blank folder to a fully functioning, production-ready SaaS prototype deployed to the cloud.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Deliverables
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;GitHub Repo:&lt;/strong&gt; &lt;a href="https://github.com/kheAI/yny-app" rel="noopener noreferrer"&gt;kheAI/yny-app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Video Demo:&lt;/strong&gt; &lt;a href="https://www.youtube.com/watch?v=FsEYWDAcwsw" rel="noopener noreferrer"&gt;Watch on YouTube&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Vercel Live Demo&lt;/strong&gt;: &lt;a href="https://yny-ui.vercel.app/" rel="noopener noreferrer"&gt;Play&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/FsEYWDAcwsw"&gt;
  &lt;/iframe&gt;
 &lt;/p&gt;
&lt;h2&gt;
  
  
  🏗️ The Architecture &amp;amp; Tech Stack (The "Why")
&lt;/h2&gt;

&lt;p&gt;To ensure data integrity, prevent our apps from becoming logically entangled, and allow independent scaling, I chose a strict &lt;strong&gt;Microservices Architecture&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Here is what we are using and why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Data Tier:&lt;/strong&gt; Google Cloud SQL (PostgreSQL). We are using the &lt;code&gt;pgvector&lt;/code&gt; extension so our database can handle &lt;em&gt;both&lt;/em&gt; standard relational data (inventory) and mathematical arrays (AI memory/embeddings) in the same place.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Logic Tier (ERP):&lt;/strong&gt; A type-safe &lt;strong&gt;.NET 8 Web API&lt;/strong&gt;. C# is the industry standard for fast, secure delivery of structured business data.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Logic Tier (AI):&lt;/strong&gt; A &lt;strong&gt;Python FastAPI&lt;/strong&gt; service. Python is the undisputed king of AI. This service executes a &lt;a href="https://ai.google.dev/gemini-api/docs/embeddings" rel="noopener noreferrer"&gt;Retrieval-Augmented Generation (RAG)&lt;/a&gt; workflow using the &lt;strong&gt;Gemini API&lt;/strong&gt; (refer Github Repo for Vertex AI version too).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Presentation Tier:&lt;/strong&gt; A responsive frontend built with &lt;strong&gt;React and Vite&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Hosting:&lt;/strong&gt; Serverless, auto-scaling backend deployments via &lt;strong&gt;Google Cloud Run&lt;/strong&gt; (meaning you only pay when people use it), with the frontend hosted on &lt;strong&gt;Vercel&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Engineer's Note on AI Models:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For this tutorial, we are utilizing the Gemini API. &lt;/li&gt;
&lt;li&gt;We'll use the &lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; for interactive apps or agents where &lt;strong&gt;low latency&lt;/strong&gt; is important. A 26B Mixture-of-Experts (MoE) model that offers fast inference by using only ~4B active parameters. It offers nearly the same intelligence as the 31B model but runs significantly faster because it only activates a fraction of its parameters (4B) per token. &lt;/li&gt;
&lt;li&gt;For Embeddings, we choose &lt;code&gt;gemini-embedding-001&lt;/code&gt; to turn our text into 768-dimensional mathematical vectors. For multimodal model, can try &lt;code&gt;gemini-embedding-2&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;The Gemini API SDK's default to &lt;code&gt;v1beta&lt;/code&gt;, but you can opt to use other versions by setting the API version &lt;code&gt;genai.Client(http_options={'api_version': 'v1'})&lt;/code&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260509-yny-gemini-api-rate-limit_nqq-NibK1.png" rel="noopener noreferrer"&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%2F3bihtggga9soibxpb0u3.png" alt="yny-gemini-api-rate-limit" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  How the System Flows
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260509-yny-workflow_bFOldGiR_.png" rel="noopener noreferrer"&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%2Ffo2h4yhz5n993t3c4yym.png" alt="yny-workflow" width="799" height="466"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  🛠️ Phase 0: Workspace Setup &amp;amp; Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before writing a single line of code, we need to set up our workbench. &lt;/p&gt;
&lt;h3&gt;
  
  
  1. The Tools You Need
&lt;/h3&gt;

&lt;p&gt;Ensure you have the following installed on your machine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Google Cloud Account:&lt;/strong&gt; Create a project (e.g., &lt;code&gt;yny-saas-2024&lt;/code&gt;). Write down your &lt;strong&gt;Project ID&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;gcloud CLI:&lt;/strong&gt; Installed and authenticated. Run &lt;code&gt;gcloud auth login&lt;/code&gt;, then &lt;code&gt;gcloud config set project YOUR_PROJECT_ID&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;.NET 8 SDK:&lt;/strong&gt; For our C# backend. Verify with &lt;code&gt;dotnet --version&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Python 3.10+:&lt;/strong&gt; For the AI service. Verify with &lt;code&gt;python3 --version&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Node.js (LTS):&lt;/strong&gt; For the React frontend. Verify with &lt;code&gt;node -v&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Gemini API Key:&lt;/strong&gt; Get one for free from &lt;a href="https://aistudio.google.com/" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  2. The Directory Structure
&lt;/h3&gt;

&lt;p&gt;Create a master folder. This will act as the "monorepo" for our three microservices.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;yny-app
&lt;span class="nb"&gt;cd &lt;/span&gt;yny-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260508-yny-app-structure_RF3iFMSJj.png" rel="noopener noreferrer"&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%2Fx3lclkv4vokd32md4nia.png" alt="yny-app-structure" width="598" height="1844"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Crucial Step:&lt;/strong&gt; Create a &lt;code&gt;.gitignore&lt;/code&gt; file in this root folder immediately. This prevents you from accidentally uploading database passwords or API keys to GitHub.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# yny-app/.gitignore
node_modules/
bin/
obj/
venv/
.env
appsettings.json
.DS_Store
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🗄️ Phase 1: The Cloud Database (Postgres + pgvector)
&lt;/h2&gt;

&lt;p&gt;We need a database capable of standard SQL (for products) and Vector Math (for the AI). &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Provision the Database
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;strong&gt;Google Cloud Console&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Cloud SQL&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Create Instance&lt;/strong&gt; -&amp;gt; &lt;strong&gt;PostgreSQL&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instance ID:&lt;/strong&gt; &lt;code&gt;yny-db-instance&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Password:&lt;/strong&gt; &lt;code&gt;YnySecurePass26&lt;/code&gt; &lt;em&gt;(Write this down! Avoid characters like &lt;code&gt;@&lt;/code&gt; or &lt;code&gt;#&lt;/code&gt; to prevent URL parsing errors).&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edition:&lt;/strong&gt; Choose &lt;strong&gt;Enterprise&lt;/strong&gt; (Sandbox/Shared Core) to keep costs near zero.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Region:&lt;/strong&gt; &lt;code&gt;us-central1&lt;/code&gt;. Click &lt;strong&gt;Create&lt;/strong&gt; (Takes ~5 minutes).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2: Seed the Schema &amp;amp; Data
&lt;/h3&gt;

&lt;p&gt;Once running, open the &lt;strong&gt;Google Cloud Shell&lt;/strong&gt; (the terminal icon at the top right of the GCP console) and connect to your database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud sql connect yny-db-instance &lt;span class="nt"&gt;--user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, paste your password. Then, run this SQL script to build your foundation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- 1. Enable pgvector for AI Memory&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- 2. Create the ERP Tables&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ProductCode&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ProductName&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Category&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;QuantityInStock&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="s1"&gt;'Active'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- 3. Create the AI Knowledge Base Table&lt;/span&gt;
&lt;span class="c1"&gt;-- Google's embeddings model outputs exactly 768 dimensions&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;manual_knowledge&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;product_code&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProductCode&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;section_title&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;text_chunk&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="n"&gt;VECTOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- 4. Insert Production-Alike ERP Data&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProductCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ProductName&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="n"&gt;QuantityInStock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'PUMP-CENT-001'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Centrifugal Pump - Model X1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Pumps'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Active'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'SENS-VIB-99'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Vibration Sensor - Wireless'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Sensors'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Active'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'VALVE-GATE-05'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Heavy Duty Gate Valve'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Valves'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Out of Stock'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- 5. Check&lt;/span&gt;
&lt;span class="c1"&gt;-- Check Your ERP Inventory (Basic)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- Filter for Critical Items (Low/No Stock)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;ProductCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ProductName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QuantityInStock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;QuantityInStock&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Out of Stock'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- Safely Check the AI Knowledge Base&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;product_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;section_title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="k"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text_chunk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;manual_snippet&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;manual_knowledge&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- Verify the AI Vector Dimensions&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;product_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;vector_dims&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;vector_dimensions&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;manual_knowledge&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- The "Big Picture" JOIN Query&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QuantityInStock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;section_title&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;AI_Manual_Available&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;manual_knowledge&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_code&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Type &lt;code&gt;\q&lt;/code&gt; and press Enter to exit. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📌 &lt;strong&gt;Take Note:&lt;/strong&gt; Go to your Cloud SQL dashboard and copy the &lt;strong&gt;Public IP&lt;/strong&gt; of your database. You will need it for the next steps.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260508-yny-postgres-insert_Un7udGH60o.png" rel="noopener noreferrer"&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%2Fi2omwsttw1c9437fan4m.png" alt="yny-postgres-insert" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260508-yny-postgres-queries_Hzubij3WJV.png" rel="noopener noreferrer"&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%2Fpffqr3ypm4xpxoxspqfn.png" alt="yny-postgres-queriesg" width="800" height="1180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚡ Phase 2: The ERP Backend (.NET 8 Web API)
&lt;/h2&gt;

&lt;p&gt;C# is my go-to for enterprise logic. It is blazingly fast and highly structured. We will build a lightweight API to serve our inventory data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Initialize the Project
&lt;/h3&gt;

&lt;p&gt;In your local terminal (inside the &lt;code&gt;yny-app&lt;/code&gt; folder):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new webapi &lt;span class="nt"&gt;-n&lt;/span&gt; yny.Api
&lt;span class="nb"&gt;cd &lt;/span&gt;yny.Api
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Database Connection String
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;yny.Api/appsettings.json&lt;/code&gt;. Configure your connection string replacing &lt;code&gt;YOUR_DB_IP&lt;/code&gt; with your database's Public IP:&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;"Logging"&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;"LogLevel"&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;"Default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Information"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Microsoft.AspNetCore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Warning"&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;"AllowedHosts"&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;"ConnectionStrings"&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;"DefaultConnection"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Host=YOUR_DB_IP;Database=postgres;Username=postgres;Password=YnySecurePass26"&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;h3&gt;
  
  
  Step 3: Write the API Logic
&lt;/h3&gt;

&lt;p&gt;We are using &lt;strong&gt;Minimal APIs&lt;/strong&gt; to keep our code clean. Open &lt;code&gt;Program.cs&lt;/code&gt; and replace &lt;em&gt;everything&lt;/em&gt; with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.EntityFrameworkCore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.ComponentModel.DataAnnotations&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.ComponentModel.DataAnnotations.Schema&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddCors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AllowAll"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithOrigins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"http://localhost:5173"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"http://localhost:3000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"https://yny-ui.vercel.app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"https://yny-ui-158766252751.us-central1.run.app"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AllowAnyHeader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AllowAnyMethod&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetConnectionString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DefaultConnection"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseNpgsql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connString&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;//.UseLowerCaseNamingConvention());&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseCors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AllowAll"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseHttpsRedirection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ERP API running"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/products"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/products/{code}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"products"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"productcode"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;ProductCode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"productname"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;ProductName&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Category&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"quantityinstock"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;QuantityInStock&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppDbContext&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DbContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbContextOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DbSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&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;&lt;em&gt;Test it:&lt;/em&gt; Run &lt;code&gt;dotnet run&lt;/code&gt;. Open your browser to &lt;code&gt;http://localhost:5000/api/products&lt;/code&gt; to see your JSON data!&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Phase 3: The AI Microservice (Python + FastAPI)
&lt;/h2&gt;

&lt;p&gt;This is the "Brain" of our application. We are using a pattern called &lt;strong&gt;RAG (Retrieval-Augmented Generation)&lt;/strong&gt;. When a user asks a question, this service turns the question into math, finds similar mathematical concepts in our Postgres database, and feeds that exact manual to the LLM to get a factual answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Python Setup
&lt;/h3&gt;

&lt;p&gt;Open a new terminal tab. Go back to your &lt;code&gt;yny-app&lt;/code&gt; root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;yny.AI
&lt;span class="nb"&gt;cd &lt;/span&gt;yny.AI
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate  &lt;span class="c"&gt;# On Windows use: venv\Scripts\activate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;requirements.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fastapi
uvicorn
psycopg2-binary
python-dotenv
google-generativeai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run: &lt;code&gt;pip install -r requirements.txt&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Configure Secrets
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in the &lt;code&gt;yny.AI&lt;/code&gt; folder (replace &lt;code&gt;YOUR_DB_IP&lt;/code&gt; and &lt;code&gt;YOUR_API_KEY&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DB_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgresql://postgres:YnySecurePass26@YOUR_DB_IP:5432/postgres
&lt;span class="nv"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YOUR_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Write the RAG Pipeline (&lt;code&gt;main.py&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;main.py&lt;/code&gt;. Notice the SQL query using &lt;code&gt;&amp;lt;=&amp;gt;&lt;/code&gt;. This is the &lt;code&gt;pgvector&lt;/code&gt; operator for &lt;em&gt;Cosine Distance&lt;/em&gt;—it calculates how closely related the user's question is to our manuals!&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HTTPException&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi.middleware.cors&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;google.generativeai&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;psycopg2&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allow_origins&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;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;allow_methods&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;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;allow_headers&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;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# Initialize Gemini
&lt;/span&gt;&lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;llm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GenerativeModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemma-4-26b-a4b-it&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="s"&gt;)

@app.get(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;)
def root():
    return {&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="n"&gt;AI&lt;/span&gt; &lt;span class="n"&gt;API&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="n"&gt;perfectly&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;}

@app.get(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;troubleshoot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;)
async def troubleshoot(question: str, product_code: str):
    try:
        # Step 1: Convert question to vector
        embedding_result = genai.embed_content(
            model=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="n"&gt;gemini&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
            content=question,
            output_dimensionality=768
        )
        query_vector = embedding_result[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;embedding&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;]

        # Step 2: Search Postgres using pgvector Cosine Distance (&amp;lt;=&amp;gt;)
        conn = psycopg2.connect(os.getenv(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="n"&gt;DB_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;))
        cur = conn.cursor()
        query = &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
            SELECT text_chunk FROM manual_knowledge 
            WHERE product_code = %s 
            ORDER BY embedding &amp;lt;=&amp;gt; %s::vector LIMIT 1
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        cur.execute(query, (product_code, query_vector))
        result = cur.fetchone()
        conn.close()

        context = result[0] if result else &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="n"&gt;No&lt;/span&gt; &lt;span class="n"&gt;manual&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;

        # Step 3: Generate answer with Gemma
        prompt = f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        You are an expert industrial maintenance AI.
        Use ONLY the following manual excerpt to answer the user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s question.
        Manual Excerpt: {context}
        User Question: {question}
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;

        response = llm.generate_content(prompt)
        return {&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: response.text}

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

if __name__ == &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="n"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:
    import uvicorn
    uvicorn.run(app, host=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, port=8080)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260508-yny-fastapi-no-rag_k7AedwVdEQ.png" rel="noopener noreferrer"&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%2Fa8obzvpnwshcdxyo8u6h.png" alt="yny-fastapi-no-rag" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Seed the AI "Brain" (&lt;code&gt;seed.py&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;To prove this works, we must inject an equipment manual into our database. Create &lt;code&gt;seed.py&lt;/code&gt;:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;google.generativeai&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;psycopg2&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;manual_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
Maintenance Manual for PUMP-CENT-001:
Issue: Crackling noise (like marbles/gravel).
Diagnosis: Pump is experiencing cavitation due to low Net Positive Suction Head.
Action: Immediately throttle the discharge valve to reduce flow rate. Torque housing bolts to 45 Nm.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Embedding text via Gemini...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;embedding_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;embed_content&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-embedding-001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;manual_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;output_dimensionality&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;768&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;embedding_result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;embedding&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Saving to PostgreSQL...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;psycopg2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DB_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;cur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INSERT INTO manual_knowledge (product_code, section_title, text_chunk, embedding) VALUES (%s, %s, %s, %s)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;PUMP-CENT-001&lt;/span&gt;&lt;span class="sh"&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;Troubleshooting: Noise&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;manual_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Vector Seeded Successfully!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;python seed.py&lt;/code&gt; once. Your database can now "think" about centrifugal pumps! Test your API by running &lt;code&gt;python main.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260508-yny-vector-embedding-seed_ul0IYCHtp.png" rel="noopener noreferrer"&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%2Feh1awl4bz84cr0m7wksr.png" alt="yny-vector-embedding-seed" width="800" height="688"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260508-yny-fastapi-rag-response_MfbEzAI2J.png" rel="noopener noreferrer"&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%2Fau7nk7x2x0wu1jw6i28j.png" alt="yny-fastapi-rag-response" width="800" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🎨 Phase 4: The Frontend UI (React + Vite)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Initialize the App
&lt;/h3&gt;

&lt;p&gt;Go back to the root &lt;code&gt;yny-app&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create vite@latest yny-ui &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--template&lt;/span&gt; react
&lt;span class="nb"&gt;cd &lt;/span&gt;yny-ui
npm &lt;span class="nb"&gt;install &lt;/span&gt;axios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Build the Dashboard (&lt;code&gt;src/App.jsx&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Replace &lt;code&gt;App.jsx&lt;/code&gt; entirely. This UI will fetch inventory from &lt;code&gt;.NET&lt;/code&gt; and query &lt;code&gt;Python&lt;/code&gt; for AI troubleshooting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactMarkdown&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-markdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;remarkGfm&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;remark-gfm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setProducts&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setQuestion&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aiAnswer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAiAnswer&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ERP_API&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_ERP_API&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://erp-api-158766252751.us-central1.run.app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AI_API&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_AI_API&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://ai-api-158766252751.us-central1.run.app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;axios&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ERP_API&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/products`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setProducts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ERP API not running&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;askAI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;productCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;AI_API&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/troubleshoot`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;product_code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;productCode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="nf"&gt;setAiAnswer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setAiAnswer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error reaching AI service.&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="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fontFamily&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;system-ui&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;900px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0 auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#0056b3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Y&lt;span class="err"&gt;&amp;amp;&lt;/span&gt;Y SaaS Dashboard&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;1. Live ERP Inventory: .NET Core (C#) + CloudSQL (PostgreSQL)&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderCollapse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;collapse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#f4f4f4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2px solid #ddd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Code&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2px solid #ddd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Name&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2px solid #ddd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Category&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2px solid #ddd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Stock&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;productCode&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1px solid #ddd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;productCode&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1px solid #ddd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;productName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1px solid #ddd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1px solid #ddd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantityInStock&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;green&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantityInStock&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;hr&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2rem 0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;2. AI Domain Expert Agent: FastAPI (Python) + Gemma (Gemini)&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.5rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1px solid #ccc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#fafafa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Target Equipment:&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; PUMP-CENT-001&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; 
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; 
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setQuestion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
          &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"e.g., Why is the pump sounding like gravel?"&lt;/span&gt; 
          &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.75rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1px solid #ccc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;boxSizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;border-box&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; 
          &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;askAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PUMP-CENT-001&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
          &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
          &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.75rem 1.5rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#0056b3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pointer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Analyzing Manuals...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Consult AI&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;aiAnswer&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.5rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#eef6ff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderLeft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4px solid #0056b3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.1rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#0056b3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;YNY Tech Agent:&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ReactMarkdown&lt;/span&gt;
                &lt;span class="na"&gt;remarkPlugins&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;remarkGfm&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="na"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.5rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.5rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#0056b3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.2rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.4rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#0056b3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h4&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.3rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#0056b3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#d9534f&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fontWeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bold&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;em&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;em&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fontStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;italic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#666&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;marginLeft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.5rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.8rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.8rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;ol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ol&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;marginLeft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.5rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.8rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.8rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;li&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.6rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#f4f4f4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2px 6px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fontFamily&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;monospace&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#d9534f&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;blockquote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;blockquote&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;borderLeft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4px solid #0056b3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;paddingLeft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginLeft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.8rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.8rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#666&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;hr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;hr&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.5rem 0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1px solid #ddd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;aiAnswer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ReactMarkdown&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;npm run dev&lt;/code&gt; and test your local full-stack masterpiece!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260509-yny-dashboard_mOo65pzNO.png" rel="noopener noreferrer"&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%2Fbc34qnumyxgnfi3yup6h.png" alt="yny-react-vite-dashboard" width="800" height="820"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Phase 5: Containerization &amp;amp; Cloud Run Deployment
&lt;/h2&gt;

&lt;p&gt;Now, we take our local code to the cloud. We will wrap our APIs in Docker containers and deploy them via Google Cloud Run (which scales to zero, saving you money!).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;The Cloud SQL Gotcha (Read This!):&lt;/strong&gt;&lt;br&gt;
Locally, you connected to Postgres via a TCP port (5432) and an IP address. In Google Cloud Run, best practice dictates you connect securely via a &lt;strong&gt;Unix domain socket&lt;/strong&gt;. &lt;br&gt;
We don't need a clunky proxy inside our Dockerfile. Google Cloud Run does this natively if we pass the right connection string!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you're the project owner, grant yourself permissions first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud projects add-iam-policy-binding YOUR_PROJECT_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--member&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;user:YourEmail@gmail.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;roles/cloudbuild.builds.editor,roles/cloudsql.client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 1: Deploying the .NET API
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;/yny.Api&lt;/code&gt;, create a clean &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mcr.microsoft.com/dotnet/sdk:8.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;dotnet publish &lt;span class="nt"&gt;-c&lt;/span&gt; Release &lt;span class="nt"&gt;-o&lt;/span&gt; out

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/dotnet/aspnet:8.0&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/out .&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; ASPNETCORE_URLS=http://+:8080&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["dotnet", "yny.Api.dll"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy it via your terminal (Replace &lt;code&gt;YOUR_PROJECT_ID&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Build and push the image to Google Container Registry&lt;/span&gt;
gcloud builds submit &lt;span class="nt"&gt;--tag&lt;/span&gt; gcr.io/YOUR_PROJECT_ID/erp-api

&lt;span class="c"&gt;# 2. Deploy to Cloud Run (Notice the new Unix Socket Connection String!)&lt;/span&gt;
gcloud run deploy erp-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--image&lt;/span&gt; gcr.io/YOUR_PROJECT_ID/erp-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-central1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--allow-unauthenticated&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--add-cloudsql-instances&lt;/span&gt; YOUR_PROJECT_ID:us-central1:yny-db-instance &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set-env-vars&lt;/span&gt; &lt;span class="nv"&gt;ConnectionStrings__DefaultConnection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Host=/cloudsql/YOUR_PROJECT_ID:us-central1:yny-db-instance;Database=postgres;Username=postgres;Password=YnySecurePass26;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Make sure to link your Cloud SQL instance to this Cloud Run service under the "Connections" tab in the GCP Console!)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Deploying the Python AI API
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;/yny.AI&lt;/code&gt;, create a &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.12-slim&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy it (Remember to use your actual Gemini API key here, or better yet, use GCP Secret Manager in production):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud builds submit &lt;span class="nt"&gt;--tag&lt;/span&gt; gcr.io/YOUR_PROJECT_ID/ai-api

gcloud run deploy ai-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--image&lt;/span&gt; gcr.io/YOUR_PROJECT_ID/ai-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-central1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--allow-unauthenticated&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--add-cloudsql-instances&lt;/span&gt; YOUR_PROJECT_ID:us-central1:yny-db-instance &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set-env-vars&lt;/span&gt; &lt;span class="nv"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_API_KEY"&lt;/span&gt;,DB_URL&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"postgresql+psycopg2://postgres:YnySecurePass26@/postgres?host=/cloudsql/YOUR_PROJECT_ID:us-central1:yny-db-instance"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260509-yny-cloudsql-cloudrun_3THwWuTPh.png" rel="noopener noreferrer"&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%2Fiq69yjukybildj3zc48w.png" alt="yny-cloudsql-cloudrun" width="799" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Deploying the Frontend to Vercel
&lt;/h3&gt;

&lt;p&gt;Take note of the URLs Cloud Run just generated for you (e.g., &lt;code&gt;https://erp-api-xyz.run.app&lt;/code&gt; and &lt;code&gt;https://ai-api-xyz.run.app&lt;/code&gt;). &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push your &lt;code&gt;yny-ui&lt;/code&gt; code to GitHub.&lt;/li&gt;
&lt;li&gt;Log into &lt;a href="https://vercel.com/dashboard" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt; and Import your repository.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Environment Variables&lt;/strong&gt;, add:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;VITE_ERP_API&lt;/code&gt; = &lt;code&gt;[Your Cloud Run .NET URL]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VITE_AI_API&lt;/code&gt; = &lt;code&gt;[Your Cloud Run Python URL]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;. Your UI is now live globally! Your UI will be live at: &lt;code&gt;https://yny-ui.vercel.app&lt;/code&gt; (or custom domain). Auto-deploys on every push to &lt;code&gt;main&lt;/code&gt; branch!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🔄 Phase 6: Level-Up to CI/CD (Bonus)
&lt;/h2&gt;

&lt;p&gt;Tired of typing gcloud commands manually? Let GitHub deploy it for you. Create &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt; in your repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Microservices&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Auth GCP&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;google-github-actions/auth@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;credentials_json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets.GCP_SA_KEY&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Cloud SDK&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;google-github-actions/setup-gcloud@v2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy .NET API&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;cd yny.Api&lt;/span&gt;
          &lt;span class="s"&gt;gcloud builds submit --tag gcr.io/${{ secrets.GCP_PROJECT_ID }}/erp-api&lt;/span&gt;
          &lt;span class="s"&gt;gcloud run deploy erp-api --image gcr.io/${{ secrets.GCP_PROJECT_ID }}/erp-api --region us-central1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(You will need to set &lt;code&gt;GCP_PROJECT_ID&lt;/code&gt; and a &lt;code&gt;GCP_SA_KEY&lt;/code&gt; in your GitHub Repository Settings -&amp;gt; Secrets).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🎤 Phase 7: The Final Demo Script
&lt;/h2&gt;

&lt;p&gt;If you are showcasing this project to stakeholders, here is the exact narrative flow I recommend:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Show the Live Dashboard:&lt;/strong&gt; &lt;em&gt;"This is the Y&amp;amp;Y SaaS Dashboard. The top section is our .NET 8 ERP pulling live operational data directly from a PostgreSQL instance."&lt;/em&gt; Point out the real-time stock levels, specifically the out-of-stock valve.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setup the Incident:&lt;/strong&gt; &lt;em&gt;"Imagine a junior engineer is on the factory floor and hears a strange crackling noise coming from &lt;code&gt;PUMP-CENT-001&lt;/code&gt;."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execute the Prompt:&lt;/strong&gt; Type: &lt;em&gt;"Why is the pump making a crackling noise like gravel and what should I do?"&lt;/em&gt; into the AI input and hit &lt;strong&gt;Consult AI&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explain the Magic:&lt;/strong&gt; &lt;em&gt;"Right now, our Python microservice is converting my question into a mathematical vector. It's querying the &lt;code&gt;pgvector&lt;/code&gt; database via Cosine Distance to retrieve the exact manufacturer maintenance manual excerpt, and passing that strict context to Google's Gemma model to synthesize a safe resolution."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Resolution:&lt;/strong&gt; The AI will output a clean, professional answer based &lt;em&gt;strictly&lt;/em&gt; on the manual we seeded (diagnosing cavitation and advising them to throttle the valve).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;By completing this build, you've successfully created a modern enterprise system. You separated concerns using microservices, connected to cloud databases, implemented the industry-standard RAG AI pattern, and utilized serverless cloud deployment. &lt;/p&gt;

&lt;p&gt;The gap between a "cool script" and an "enterprise system" is architecture. And you just built it. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy Coding!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>gemmachallenge</category>
      <category>gemma</category>
    </item>
    <item>
      <title>Building a Systemic Autonomy Agent: OpenClaw + Gemma 4 &amp; TurboQuant on Raspberry Pi 4B</title>
      <dc:creator>Khe Ai</dc:creator>
      <pubDate>Sat, 09 May 2026 06:20:02 +0000</pubDate>
      <link>https://dev.to/kheai/building-a-systemic-autonomy-agent-openclaw-gemma-4-turboquant-on-raspberry-pi-4b-49jk</link>
      <guid>https://dev.to/kheai/building-a-systemic-autonomy-agent-openclaw-gemma-4-turboquant-on-raspberry-pi-4b-49jk</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-gemma-2026-05-06"&gt;Gemma 4 Challenge: Write About Gemma 4&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you’re reading this, you probably want to run a local, autonomous AI agent but might feel overwhelmed by the hardware requirements or complex software stacks. I was in exactly the same boat. I wanted to build an autonomous agent using OpenClaw, governed by the ethical and systemic framework of the KheAi Protocol, but I wanted it running entirely at the edge—specifically, on a Raspberry Pi 4B.&lt;/p&gt;

&lt;p&gt;After a lot of trial, error, and compiling, I successfully turned my Raspberry Pi 4B (8GB RAM, 120GB SSD boot) into a highly efficient edge brain running Gemma 4 (e2b) optimized with TurboQuant.&lt;/p&gt;

&lt;p&gt;Here is exactly how I did it, step-by-step, so you can follow along even if you are a total beginner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/ai/260419-openclaw-rpi-gemma4-turboquant-guide_luIuw0iV5.png" rel="noopener noreferrer"&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%2F2ng8j0tktss742x6k77v.png" alt="Building a Systemic Autonomy Agent: OpenClaw + Gemma 4 &amp;amp; TurboQuant on Raspberry Pi 4B" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Master Plan: What We Are Building
&lt;/h2&gt;

&lt;p&gt;Before diving into the terminal commands, let's break down the architecture of what we are building:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Hardware (The Body):&lt;/strong&gt; A Raspberry Pi 4B (8GB RAM). Crucially, we are booting from a 120GB SSD, not a MicroSD card. If you want an agent that reads and writes data constantly, an SD card will bottleneck your speed and eventually corrupt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Mind (The LLM):&lt;/strong&gt; Gemma 4 E2B (specifically the &lt;code&gt;Q4_K_M&lt;/code&gt; quantization). This is a highly capable Small Language Model (SLM) fine-tuned for code execution and tool use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Optimizer (TurboQuant):&lt;/strong&gt; Running a modern LLM on 8GB of RAM is tight. We will use a custom branch of &lt;code&gt;llama.cpp&lt;/code&gt; featuring TurboQuant, which dynamically compresses the model's "short-term memory" (KV Cache), preventing our Pi from crashing during long conversations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Soul (KheAi Protocol):&lt;/strong&gt; Instead of a generic "hacking" persona, we will govern our OpenClaw agent using the KheAi Protocol—a framework for Systemic Autonomy. This gives the agent a structured, ethical, and goal-oriented operating system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Networking (Optional):&lt;/strong&gt; Tailscale for a Zero Trust Mesh Network. This allows secure, remote access to the OpenClaw dashboard and local terminal without exposing ports to the public internet.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's get your edge agent alive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 1: Hardware &amp;amp; OS Foundation (The Body)
&lt;/h2&gt;

&lt;p&gt;Before we touch the AI, we need a stable "nervous system."&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 Boot from SSD (Non-Negotiable)
&lt;/h3&gt;

&lt;p&gt;Running an autonomous agent on a MicroSD card will kill the card within weeks due to high read/write cycles and slow down the LLM's "thinking" time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; Use Raspberry Pi Imager to flash &lt;a href="https://dev.to/posts/step-by-step-guide-to-setup-popebot-in-my-rpi"&gt;&lt;strong&gt;Raspberry Pi OS (64-bit)&lt;/strong&gt;&lt;/a&gt; onto your 120GB SSD.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimization:&lt;/strong&gt; In the settings, enable SSH and set your username/password.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1.2 Thermal Management
&lt;/h3&gt;

&lt;p&gt;The Pi 4B will throttle (slow down) at 80°C, the "Brain" slows down, and OpenClaw might time out. Compiling LLMs and running inference will hit this within minutes. &lt;strong&gt;Requirement:&lt;/strong&gt; You &lt;strong&gt;must&lt;/strong&gt; use a heatsink and fan. Check your temp with &lt;code&gt;vcgencmd measure_temp&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.3 Tuning the OS
&lt;/h3&gt;

&lt;p&gt;Once logged in via SSH, optimize the memory and clock speed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="c"&gt;# Increase Swap to 4GB to handle model spikes&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;dphys-swapfile swapoff
&lt;span class="nb"&gt;sudo sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s/CONF_SWAPSIZE=100/CONF_SWAPSIZE=4096/'&lt;/span&gt; /etc/dphys-swapfile
&lt;span class="nb"&gt;sudo &lt;/span&gt;dphys-swapfile setup
&lt;span class="nb"&gt;sudo &lt;/span&gt;dphys-swapfile swapon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Phase 2: Compiling the Edge Brain (llama-cpp-turboquant)
&lt;/h2&gt;

&lt;p&gt;Standard LLM engines eat too much RAM. We are going to build a specialized version of &lt;code&gt;llama.cpp&lt;/code&gt; that uses &lt;strong&gt;TurboQuant KV Cache compression&lt;/strong&gt;. This allows Gemma 4 to handle long conversations without crashing the Pi.&lt;/p&gt;

&lt;p&gt;First, we need the tools to build the software. We will also install &lt;code&gt;libssl-dev&lt;/code&gt; to prevent any OpenSSL errors during the build process, and &lt;code&gt;libopenblas-dev&lt;/code&gt; for fast matrix math.&lt;/p&gt;

&lt;p&gt;Standard &lt;code&gt;llama.cpp&lt;/code&gt; builds might not have the specific cache compression flags we need. We will pull from a community fork and check out the exact branch where KV cache compression is being actively developed.&lt;/p&gt;

&lt;p&gt;The Raspberry Pi 4 uses a Cortex-A72 chip (ARMv8). The flag &lt;code&gt;-DGGML_NEON=ON&lt;/code&gt; is absolutely essential here—it tells the compiler to use the Pi's SIMD (Single Instruction, Multiple Data) instructions, which acts as the primary hardware accelerator for our math operations.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note: Don't use newer flags like &lt;code&gt;ARM_KLEIDIAI&lt;/code&gt;; those are for ARMv9 and won't help you here).&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Build from Source
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; git cmake build-essential libopenblas-dev libssl-dev

&lt;span class="c"&gt;# Clone the TurboQuant-specific branch&lt;/span&gt;
git clone https://github.com/TheTom/llama-cpp-turboquant
&lt;span class="nb"&gt;cd &lt;/span&gt;llama-cpp-turboquant
git checkout feature/turboquant-kv-cache

&lt;span class="c"&gt;# Configure for Pi 4 (Cortex-A72 / NEON acceleration)&lt;/span&gt;
cmake &lt;span class="nt"&gt;-B&lt;/span&gt; build &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DCMAKE_BUILD_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Release &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DGGML_CPU&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DGGML_NATIVE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DGGML_OPENBLAS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DGGML_NEON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DLLAMA_OPENSSL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON

&lt;span class="c"&gt;# Compile (This takes ~15 mins)&lt;/span&gt;
cmake &lt;span class="nt"&gt;--build&lt;/span&gt; build &lt;span class="nt"&gt;--config&lt;/span&gt; Release &lt;span class="nt"&gt;-j4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key Considerations for Raspberry Pi 4&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NEON Acceleration&lt;/strong&gt;: The &lt;code&gt;-DGGML_NEON=ON&lt;/code&gt; flag is essential for the Pi 4 to utilize its SIMD instructions for faster math. This is the primary hardware accelerator for ARMv8 chips like the one in the Raspberry Pi 4. Newer flags like &lt;code&gt;ARM_KLEIDIAI&lt;/code&gt; target ARMv9 and won't benefit your hardware.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;KV Cache Savings&lt;/strong&gt;: TurboQuant's primary benefit on a Pi 4 (especially 4GB models) is reducing the memory footprint of the KV cache, allowing you to use longer contexts without hitting swap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wait for Compile&lt;/strong&gt;: Building on a Pi 4 can take 10–20 minutes. Ensure you have adequate cooling, as all 4 cores will be at 100% load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TurboQuant Branch&lt;/strong&gt;: &lt;strong&gt;&lt;code&gt;git checkout feature/turboquant-kv-cache&lt;/code&gt;&lt;/strong&gt;: This is the active development branch where the &lt;code&gt;--cache-type-k&lt;/code&gt; and &lt;code&gt;--cache-type-v&lt;/code&gt; flags are implemented.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TurboQuant Flags&lt;/strong&gt;: Once built, you can run your model with &lt;code&gt;-ctk turbo4 -ctv turbo4&lt;/code&gt; to significantly reduce RAM usage during long conversations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2iji9eus1v2okywnl923.jpg" rel="noopener noreferrer"&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%2F2iji9eus1v2okywnl923.jpg" alt="ssh rpi for llma.cpp" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Take a break.&lt;/strong&gt; Compiling on all 4 cores will push your Pi to 100% CPU load and can take 10 to 20 minutes. Ensure your Pi has decent cooling (a small fan or heatsink).&lt;/p&gt;

&lt;p&gt;Once finished, verify that the new cache types exist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./build/bin/llama-cli &lt;span class="nt"&gt;--help&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;cache-type
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see &lt;code&gt;turbo4&lt;/code&gt; listed in the output, congratulations! Your edge engine is ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 3: Sourcing the Brain (Gemma 4 Q4_K_M)
&lt;/h2&gt;

&lt;p&gt;Next, we need the actual model weights. We will use the &lt;a href="https://huggingface.co/unsloth/gemma-4-E2B-it-GGUF" rel="noopener noreferrer"&gt;&lt;code&gt;gemma-4-E2B-it-GGUF&lt;/code&gt;&lt;/a&gt; model.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Quick Lesson on Quantization (Why we use Q4_K_M + TurboQuant)
&lt;/h3&gt;

&lt;p&gt;Before you download, it is crucial to understand the two different types of "shrinking" we are doing to make this fit on a Pi:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Weight Quantization (&lt;code&gt;Q4_K_M.gguf&lt;/code&gt;):&lt;/strong&gt; This compresses the model's &lt;strong&gt;permanent weights&lt;/strong&gt; (its long-term memory). The file you download is already shrunk from 16-bit to roughly 4-bit. This is what allows a multi-billion parameter model to sit comfortably on your SD card or SSD.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;KV Cache Quantization (TurboQuant):&lt;/strong&gt; This compresses the model's &lt;strong&gt;short-term memory&lt;/strong&gt; (the scratchpad it uses &lt;em&gt;while&lt;/em&gt; you are chatting). TurboQuant isn't a file you download; it’s an active efficiency mode you toggle on when running the server to stop RAM usage from ballooning as context grows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Option 1: Install via OpenSSL Development Headers (ODHs)
&lt;/h3&gt;

&lt;p&gt;Run this in your &lt;code&gt;llama-cpp-turboquant&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./build/bin/llama-cli &lt;span class="nt"&gt;-hf&lt;/span&gt; unsloth/gemma-4-E2B-it-GGUF:Q4_K_M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option 2: Download the Model Manually
&lt;/h3&gt;

&lt;p&gt;Alternatively,  to avoid messing with Python scripts or SSL library issues, let's just grab the file directly via the terminal using &lt;code&gt;wget&lt;/code&gt; (or &lt;code&gt;curl&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://huggingface.co/unsloth/gemma-4-E2B-it-GGUF/resolve/main/gemma-4-E2B-it-Q4_K_M.gguf &lt;span class="nt"&gt;-O&lt;/span&gt; models/gemma-4-E2B-it-Q4_K_M.gguf

curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://huggingface.co/unsloth/Qwen3.5-0.8B-GGUF/resolve/main/Qwen3.5-0.8B-Q4_K_S.gguf &lt;span class="nt"&gt;-o&lt;/span&gt; models/Qwen3.5-0.8B-Q4_K_S.gguf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(If you prefer Qwen3.5 as a lighter alternative, you can swap the URL for a &lt;a href="///posts/run-popebot-local-qwen-3.5-2b-rpi"&gt;Qwen 0.8B GGUF&lt;/a&gt; file, but Gemma 4 E2B is specifically tuned for agentic tasks).&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Local Test Run
&lt;/h3&gt;

&lt;p&gt;Before hooking this up to OpenClaw, let's test it in the command line using &lt;code&gt;llama-cli&lt;/code&gt;. We will pass in all our optimization flags. Either via &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ODHs&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./build/bin/llama-cli &lt;span class="nt"&gt;-hf&lt;/span&gt; unsloth/gemma-4-E2B-it-GGUF:Q4_K_M &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; 4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; 4096 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-b&lt;/span&gt; 128 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--temp&lt;/span&gt; 0.1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--chat-template-kwargs&lt;/span&gt; &lt;span class="s1"&gt;'{"enable_thinking":false}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cache-type-k&lt;/span&gt; turbo4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cache-type-v&lt;/span&gt; turbo4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-fa&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-sys&lt;/span&gt; &lt;span class="s2"&gt;"You are a Stoic logic engine. Be concise."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-cnv&lt;/span&gt; &lt;span class="nt"&gt;--color&lt;/span&gt; auto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Manual&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./build/bin/llama-cli &lt;span class="nt"&gt;-m&lt;/span&gt; models/gemma-4-E2B-it-Q4_K_M.gguf &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; 4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; 4096 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-b&lt;/span&gt; 128 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--temp&lt;/span&gt; 0.1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cache-type-k&lt;/span&gt; turbo4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cache-type-v&lt;/span&gt; turbo4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-fa&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-sys&lt;/span&gt; &lt;span class="s2"&gt;"You are an autonomous agent operating under the KheAi Protocol. Be concise."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-cnv&lt;/span&gt; &lt;span class="nt"&gt;--color&lt;/span&gt; auto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./build/bin/llama-cli &lt;span class="nt"&gt;-m&lt;/span&gt; models/Qwen3.5-0.8B-Q4_K_S.gguf &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; 4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; 4096 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-b&lt;/span&gt; 128 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--temp&lt;/span&gt; 0.1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--reasoning-budget&lt;/span&gt; 0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cache-type-k&lt;/span&gt; turbo4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cache-type-v&lt;/span&gt; turbo4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-fa&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-sys&lt;/span&gt; &lt;span class="s2"&gt;"Be concise."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-cnv&lt;/span&gt; &lt;span class="nt"&gt;--color&lt;/span&gt; auto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Let’s break down the magic flags:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-t 4&lt;/code&gt;: Uses all 4 CPU threads.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-c 4096&lt;/code&gt;: Gives the model a 4K context window (plenty for agent logs). Below 1,000 tokens, TurboQuant's memory savings are negligible. The 4K mark is exactly where compressing the KV cache to 4-bits starts to dramatically save RAM, keeping the Node.js OpenClaw process and the OS from fighting over the Pi's 8GB limit.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--cache-type-k turbo4&lt;/code&gt; &amp;amp; &lt;code&gt;--cache-type-v turbo4&lt;/code&gt;: This is TurboQuant in action! It compresses the Keys and Values in the cache to 4-bit polar coordinates.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-fa on&lt;/code&gt; (Flash Attention): &lt;strong&gt;Crucial.&lt;/strong&gt; TurboQuant requires Flash Attention to be enabled to function correctly with the compressed blocks.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--reasoning-budget 0&lt;/code&gt;: Forces the model to skip lengthy internal monologues and looping, outputting direct, actionable responses.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Spinning up the Server for OpenClaw
&lt;/h3&gt;

&lt;p&gt;OpenClaw needs an API to talk to. We will launch &lt;code&gt;llama-server&lt;/code&gt; to act as an OpenAI-compatible backend, hosted directly on your Pi.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./build/bin/llama-server &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-m&lt;/span&gt; models/gemma-4-E2B-it-Q4_K_M.gguf &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--port&lt;/span&gt; 8080 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; 4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; 4096 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-b&lt;/span&gt; 128 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cache-type-k&lt;/span&gt; turbo4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cache-type-v&lt;/span&gt; turbo4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-fa&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--api-key&lt;/span&gt; &lt;span class="s2"&gt;"local-pi-key"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--host&lt;/span&gt; 0.0.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your Raspberry Pi is now acting as a dedicated, local AI server. It is listening on port &lt;code&gt;8080&lt;/code&gt; and is accessible from any machine on your local network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 4: The OpenClaw Setup &amp;amp; Onboarding (The Hands)
&lt;/h2&gt;

&lt;p&gt;OpenClaw is a Node.js-based autonomous framework. We will use the official one-liner but then manually "onboard" it to our local brain.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1 Installation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://openclaw.ai/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2 The Onboarding Wizard (Crucial Step)
&lt;/h3&gt;

&lt;p&gt;This is where we connect the framework to our Pi's local server. Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openclaw onboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Follow these specific inputs for local autonomy:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Provider:&lt;/strong&gt; Select &lt;code&gt;OpenAI Compatible&lt;/code&gt; (Since &lt;code&gt;llama-server&lt;/code&gt; mimics this).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Key:&lt;/strong&gt; Enter &lt;code&gt;local-pi-key&lt;/code&gt; (or anything, it’s local).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base URL:&lt;/strong&gt; &lt;code&gt;http://127.0.0.1:8080/v1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model:&lt;/strong&gt; &lt;code&gt;gemma-4-E2B-it-Q4_K_M&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools:&lt;/strong&gt; Enable &lt;code&gt;Terminal&lt;/code&gt; and &lt;code&gt;Filesystem&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sandbox:&lt;/strong&gt; Since we are using Gemma 4 &lt;strong&gt;E2B&lt;/strong&gt;, you should ideally provide an &lt;a href="https://e2b.dev/" rel="noopener noreferrer"&gt;E2B.dev&lt;/a&gt; API key if you want the agent to execute code in a secure, cloud-hosted sandbox. If you want it 100% local, select &lt;code&gt;Local Terminal&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Phase 5: Activating the KheAi Protocol (The Soul)
&lt;/h2&gt;

&lt;p&gt;We don't want a generic assistant. We want a systemic autonomous agent. We achieve this by overriding the OpenClaw "Persona."&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Navigate to your OpenClaw config directory: &lt;code&gt;cd ~/.openclaw&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create/Edit your system prompt: &lt;code&gt;nano SOUL.md&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Paste the &lt;a href="https://www.kheai.com/posts/kheai-protocol-systemic-autonomy-architecture" rel="noopener noreferrer"&gt;&lt;strong&gt;KheAi Protocol Architecture&lt;/strong&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;   ## KheAi Protocol v1.0

   &lt;span class="gs"&gt;**Core Identity:**&lt;/span&gt; You are a Systemic Autonomy Agent.

   &lt;span class="gs"&gt;**Operational Framework (OODA):**&lt;/span&gt; &amp;gt; - &lt;span class="gs"&gt;**Observe:**&lt;/span&gt; Scan the local environment/files.
&lt;span class="p"&gt;
   -&lt;/span&gt; &lt;span class="gs"&gt;**Orient:**&lt;/span&gt; Check Pi resource constraints (RAM/Temp).
&lt;span class="p"&gt;   -&lt;/span&gt; &lt;span class="gs"&gt;**Decide:**&lt;/span&gt; Choose the tool that uses the least energy.
&lt;span class="p"&gt;   -&lt;/span&gt; &lt;span class="gs"&gt;**Act:**&lt;/span&gt; Execute and verify.

   &lt;span class="gs"&gt;**Constraint:**&lt;/span&gt; You are running on a Raspberry Pi 4. Be concise. Do not loop. Use TurboQuant awareness for long contexts.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without the KheAi OODA (Observe, Orient, Decide, Act) constraint, a generic model might hallucinate tools or try to write long-winded python scripts. The protocol forces it to act like a machine, not a chatbot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 6: Launching the System Again
&lt;/h2&gt;

&lt;p&gt;You need two terminal windows (or use &lt;code&gt;tmux&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Terminal 1: The Brain (Server)
&lt;/h3&gt;

&lt;p&gt;Start the model with the TurboQuant flags to compress the memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./build/bin/llama-server &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-m&lt;/span&gt; models/gemma-4-E2B-it-Q4_K_M.gguf &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--port&lt;/span&gt; 8080 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; 4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt; 4096 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cache-type-k&lt;/span&gt; turbo4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cache-type-v&lt;/span&gt; turbo4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--reasoning-budget&lt;/span&gt; 0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-fa&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: &lt;code&gt;--cache-type-k turbo4&lt;/code&gt; shrinks the "short-term memory" by 4x so you don't run out of 8GB RAM.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Terminal 2: The Framework (OpenClaw)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openclaw start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Phase 7: Remote Access with Tailscale
&lt;/h2&gt;

&lt;p&gt;Once your Raspberry Pi is running an autonomous agent, you don’t want it tied to a monitor and keyboard on your desk. You want it running "headless" (plugged into power and network only) in a closet or next to your router. &lt;/p&gt;

&lt;p&gt;However, exposing your local Pi to the public internet via port forwarding is a massive security risk. Instead, we will use Tailscale to create a Zero Trust Mesh Network. This creates a secure, private tunnel between your laptop/phone and your Pi, allowing you to SSH into it or access OpenClaw from a coffee shop halfway across the world.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.1 Installation
&lt;/h3&gt;

&lt;p&gt;Run this simple one-liner on your Pi to download and install Tailscale:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://tailscale.com/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7.2 Activation &amp;amp; Authentication
&lt;/h3&gt;

&lt;p&gt;Once installed, bring the network interface up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;tailscale up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will output a URL. Copy and paste that URL into a browser on your main computer to authenticate the Pi with your Tailscale account (it's free for personal use). &lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;tailscale ip -4&lt;/code&gt; to get your Pi’s new secure IP address. You can now securely SSH into your Pi (&lt;code&gt;ssh pi@[tailscale-ip]&lt;/code&gt;) or access your agent dashboards remotely without opening a single port on your home router.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 8: Hybrid Cloud-Edge (Switching to the Gemini API)
&lt;/h2&gt;

&lt;p&gt;Running everything locally on a Pi is an incredible achievement for privacy and independence. But what if your agent encounters a task that requires massive reasoning power, deep web research, or complex code generation that Gemma 4 Q4_K_M struggles with? &lt;/p&gt;

&lt;p&gt;This is where a &lt;strong&gt;Hybrid Architecture&lt;/strong&gt; shines. You use the local edge model as your primary driver for simple, continuous tasks, and switch to a frontier cloud model like the Gemini API for the "heavy lifting." &lt;/p&gt;

&lt;h3&gt;
  
  
  The Strategy: Local for Actions, Gemini for Deep Reasoning
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primary (Local Gemma 4):&lt;/strong&gt; Use this for file scanning, basic terminal commands, navigating the OS, and formatting data. It is free, private, and fast enough for OODA loop execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fallback/Heavy Lifting (Gemini API):&lt;/strong&gt; Route tasks here when the agent needs to write complex Python scripts, analyze large datasets, or process visual information. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  8.1 Getting the Gemini API Key
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://aistudio.google.com/" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt; and sign in.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Get API Key&lt;/strong&gt; and generate a new key. Keep this secure.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  8.2 Re-configuring OpenClaw
&lt;/h3&gt;

&lt;p&gt;To switch your agent's brain over to Gemini, you simply need to run the onboarding wizard again (or edit your OpenClaw config file directly).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openclaw onboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Follow these inputs for the Cloud-Heavy setup:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Provider:&lt;/strong&gt; Select &lt;code&gt;Google&lt;/code&gt; or &lt;code&gt;Gemini&lt;/code&gt; (depending on your OpenClaw version).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Key:&lt;/strong&gt; Paste your Gemini API key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model:&lt;/strong&gt; Select &lt;code&gt;gemini-2.5-pro&lt;/code&gt; (for maximum reasoning and coding capabilities) or &lt;code&gt;gemini-2.5-flash&lt;/code&gt; (for high speed and lower cost).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools &amp;amp; Sandbox:&lt;/strong&gt; Keep these the same as Phase 4.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By swapping the provider, your agent instantly upgrades its cognitive capabilities while still utilizing the Pi as its physical "body" to execute terminal commands and interact with the local environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Building an autonomous agent entirely at the edge used to require expensive gaming laptops. By combining the affordability of a Raspberry Pi 4, the tailored intelligence of Gemma 4 E2B, and the incredible memory-saving techniques of TurboQuant, you now have a self-contained AI brain sitting on your desk.&lt;/p&gt;

&lt;p&gt;It takes patience to compile and tune, but once that server says "HTTP server listening," the feeling of having a localized, private, and fully autonomous intelligence under your control is unmatched.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Team Submissions&lt;/strong&gt;: &lt;a class="mentioned-user" href="https://dev.to/kheai"&gt;@kheai&lt;/a&gt; &lt;a class="mentioned-user" href="https://dev.to/yeemun122"&gt;@yeemun122&lt;/a&gt; &lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>gemmachallenge</category>
      <category>gemma</category>
      <category>kheai</category>
    </item>
    <item>
      <title>AI-Powered ERP System with Gemma 26B MoE</title>
      <dc:creator>Khe Ai</dc:creator>
      <pubDate>Fri, 08 May 2026 18:49:02 +0000</pubDate>
      <link>https://dev.to/kheai/ai-powered-erp-system-with-gemma-26b-moe-2l5i</link>
      <guid>https://dev.to/kheai/ai-powered-erp-system-with-gemma-26b-moe-2l5i</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-gemma-2026-05-06"&gt;Gemma 4 Challenge: Build with Gemma 4&lt;/a&gt;&lt;/em&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%2Fdq4oqiihrjp4vn1t3zoz.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%2Fdq4oqiihrjp4vn1t3zoz.png" alt="AI-Powered ERP System with Gemma 26B MoE" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Don’t just track your equipment—troubleshoot it.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;I built the &lt;strong&gt;Y&amp;amp;Y App&lt;/strong&gt;: an industrial-grade, microservices-based SaaS that merges live ERP inventory management with a state-of-the-art &lt;strong&gt;AI Domain-Expert Agent&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260509-yny-dashboard_mOo65pzNO.png" rel="noopener noreferrer"&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%2Fbc34qnumyxgnfi3yup6h.png" alt="yny-react-vite-dashboard" width="800" height="820"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt; Factory floors and industrial sites suffer from massive financial losses during equipment downtime. When machinery fails, junior engineers often waste critical hours digging through dense, hundreds-of-pages-long OEM manuals to diagnose obscure faults. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution:&lt;/strong&gt; I engineered a system where a user can view their live inventory and literally ask the system, &lt;em&gt;"Why is PUMP-CENT-001 making a crackling noise like gravel?"&lt;/em&gt; The app uses a highly structured Retrieval-Augmented Generation (RAG) pipeline to instantly retrieve the exact manufacturer manual excerpt and synthesize an accurate, safe resolution. &lt;/p&gt;

&lt;p&gt;By separating concerns into a strict microservices architecture—.NET 8 for the ERP business logic, Python (FastAPI) for the AI brain, and React for the UI—I've created an enterprise-ready blueprint that is scalable, maintainable, and blazingly fast.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260509-yny-workflow_bFOldGiR_.png" rel="noopener noreferrer"&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%2Ffo2h4yhz5n993t3c4yym.png" alt="yny-workflow" width="799" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260509-yny-cloudsql-cloudrun_3THwWuTPh.png" rel="noopener noreferrer"&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%2Fiq69yjukybildj3zc48w.png" alt="yny-cloudsql-cloudrun" width="799" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Live Web App:&lt;/strong&gt; &lt;a href="https://yny-ui.vercel.app/" rel="noopener noreferrer"&gt;Play with the Y&amp;amp;Y App on Vercel&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Video Walkthrough
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pure Gemini API&lt;/strong&gt;&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/FsEYWDAcwsw"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vertex AI&lt;/strong&gt; &lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/JHX0fRmJuW4"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

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


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kheAI" rel="noopener noreferrer"&gt;
        kheAI
      &lt;/a&gt; / &lt;a href="https://github.com/kheAI/yny-app" rel="noopener noreferrer"&gt;
        yny-app
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🏗️ Y&amp;amp;Y App – AI-Powered Industrial ERP&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://yny-ui.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d1d955c50a2cf960d0e0c391268d22a8d1771472c7f839375f5c9f42a9a58bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6976652d44656d6f2d627269676874677265656e2e7376673f7374796c653d666f722d7468652d6261646765" alt="Live Demo"&gt;&lt;/a&gt;
&lt;a href="https://www.youtube.com/watch?v=JHX0fRmJuW4" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f3fec6f453a3c18e1fd3145ea16b368719f761601ea58dccd013997756a56364/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f596f75547562652d566964656f5f44656d6f2d7265642e7376673f7374796c653d666f722d7468652d6261646765266c6f676f3d796f7574756265" alt="YouTube"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An industrial-grade, microservices-based SaaS that combines live ERP inventory management with a state-of-the-art &lt;strong&gt;AI Domain-Expert Agent&lt;/strong&gt; capable of diagnosing machinery issues in real-time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Building monolithic apps is a thing of the past. Y&amp;amp;Y App showcases a robust, strictly decoupled &lt;strong&gt;Microservices Architecture&lt;/strong&gt;, separating enterprise business logic (inventory) from complex AI workflows (Retrieval-Augmented Generation), all unified under a blazing-fast React frontend.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ The Elevator Pitch&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Don't just track your equipment—&lt;em&gt;troubleshoot it&lt;/em&gt;. Y&amp;amp;Y App uses a &lt;strong&gt;Retrieval-Augmented Generation (RAG)&lt;/strong&gt; pipeline powered by Google's Gemini APIs and PostgreSQL &lt;code&gt;pgvector&lt;/code&gt;. When a user reports a strange noise from a pump, the AI doesn't guess; it performs a vector similarity search to retrieve the exact manufacturer maintenance manual and synthesizes a safe, factual resolution.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚀 Key Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Microservices Architecture:&lt;/strong&gt; Independent scaling for UI, ERP, and AI logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise-Grade ERP API:&lt;/strong&gt; Built with &lt;strong&gt;.NET 8 Minimal&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kheAI/yny-app" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Used Gemma 4
&lt;/h2&gt;

&lt;p&gt;To make this industrial AI reliable and fast, I built a custom Retrieval-Augmented Generation (RAG) pipeline powered by Gemma 4. &lt;/p&gt;

&lt;p&gt;Here is exactly how I integrated the models into my Python microservice:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Brain: &lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
I chose the &lt;strong&gt;Gemma 4 26B MoE (Mixture-of-Experts)&lt;/strong&gt; model for the core reasoning engine. In industrial environments, precision and speed are non-negotiable. If a centrifugal pump is cavitating, an engineer needs the remediation steps &lt;em&gt;immediately&lt;/em&gt; before catastrophic failure occurs. &lt;/p&gt;

&lt;p&gt;Because &lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; utilizes an MoE architecture, it provides the deep intelligence and reasoning capabilities of a massive 26-billion parameter model, but achieves &lt;strong&gt;ultra-low latency&lt;/strong&gt; by only activating a fraction of its parameters (~4B) during inference. This was the absolute perfect fit for a real-time conversational agent where users are waiting on the UI for critical answers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The Memory: &lt;code&gt;gemini-embedding-001&lt;/code&gt; and PostgreSQL &lt;code&gt;pgvector&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
To prevent hallucinations—which are dangerous in industrial maintenance—the AI is strictly grounded in actual equipment manuals. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  When a user asks a question, my Python FastAPI service uses the &lt;code&gt;gemini-embedding-001&lt;/code&gt; model to turn the text into a 768-dimensional mathematical vector. &lt;/li&gt;
&lt;li&gt;  I then run a Cosine Distance (&lt;code&gt;&amp;lt;=&amp;gt;&lt;/code&gt;) SQL query against my Google Cloud SQL PostgreSQL database (using the &lt;code&gt;pgvector&lt;/code&gt; extension) to find the most mathematically similar equipment manual chunk.&lt;/li&gt;
&lt;li&gt;  Finally, that strict context is passed via prompt engineering to the &lt;strong&gt;Gemma 4&lt;/strong&gt; model, instructing it to act as an expert industrial maintenance AI and synthesize an answer &lt;em&gt;only&lt;/em&gt; using the provided manual.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Result:&lt;/strong&gt; A lightning-fast, highly intelligent, hallucination-free AI assistant that turns an overwhelming physical manual into an interactive, real-time problem solver.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260509-yny-gemini-api-rate-limit_nqq-NibK1.png" rel="noopener noreferrer"&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%2F3bihtggga9soibxpb0u3.png" alt="yny-gemini-api-rate-limit" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;If you are showcasing this project to stakeholders, here is the exact narrative flow I recommend:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Show the Live Dashboard:&lt;/strong&gt; &lt;em&gt;"This is the Y&amp;amp;Y SaaS Dashboard. The top section is our .NET 8 ERP pulling live operational data directly from a PostgreSQL instance."&lt;/em&gt; Point out the real-time stock levels, specifically the out-of-stock valve.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setup the Incident:&lt;/strong&gt; &lt;em&gt;"Imagine a junior engineer is on the factory floor and hears a strange crackling noise coming from &lt;code&gt;PUMP-CENT-001&lt;/code&gt;."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execute the Prompt:&lt;/strong&gt; Type: &lt;em&gt;"Why is the pump making a crackling noise like gravel and what should I do?"&lt;/em&gt; into the AI input and hit &lt;strong&gt;Consult AI&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explain the Magic:&lt;/strong&gt; &lt;em&gt;"Right now, our Python microservice is converting my question into a mathematical vector. It's querying the &lt;code&gt;pgvector&lt;/code&gt; database via Cosine Distance to retrieve the exact manufacturer maintenance manual excerpt, and passing that strict context to Google's Gemma model to synthesize a safe resolution."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Resolution:&lt;/strong&gt; The AI will output a clean, professional answer based &lt;em&gt;strictly&lt;/em&gt; on the manual we seeded (diagnosing cavitation and advising them to throttle the valve).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Team Submissions&lt;/strong&gt;: &lt;a class="mentioned-user" href="https://dev.to/kheai"&gt;@kheai&lt;/a&gt; &lt;a class="mentioned-user" href="https://dev.to/yeemun122"&gt;@yeemun122&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>gemmachallenge</category>
      <category>gemma</category>
      <category>kheai</category>
    </item>
    <item>
      <title>Blaze 3 Unofficial Simple Todos Tutorial with Meteor 3.4.1 + Rspack + PicoCSS</title>
      <dc:creator>Khe Ai</dc:creator>
      <pubDate>Fri, 08 May 2026 12:02:03 +0000</pubDate>
      <link>https://dev.to/kheai/blaze-3-unofficial-simple-todos-tutorial-with-meteor-341-rspack-picocss-52n7</link>
      <guid>https://dev.to/kheai/blaze-3-unofficial-simple-todos-tutorial-with-meteor-341-rspack-picocss-52n7</guid>
      <description>&lt;p&gt;Welcome! In this tutorial, we will create a simple To-Do app using &lt;a href="https://www.blazejs.org/" rel="noopener noreferrer"&gt;Blaze&lt;/a&gt; and Meteor 3.4.1.&lt;/p&gt;

&lt;p&gt;Blaze is Meteor's original, deeply integrated UI framework. It uses an easy-to-learn, Handlebars-like template syntax. Compared to traditional tools, Blaze eliminates the need to manually update the DOM when your database changes. Instead, it integrates directly with Meteor's transparent reactivity. Change a document in your database, and the UI updates instantly.&lt;/p&gt;

&lt;p&gt;With Meteor, a single developer can build a fully functional, real-time app in the time it takes a team of architects to decide on their communication protocols. Let's start building.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/tutorial/260508-meteor-blaze-todos-picocss_TVHhkNguw.png" rel="noopener noreferrer"&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%2Fef8mt8fsi8zlna6hs7kb.png" alt="Blaze 3 Unofficial Simple Todos Tutorial with Meteor 3.4.1 + Rspack + PicoCSS" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PS: &lt;em&gt;Tutorial originally adapted from the official&lt;/em&gt; &lt;a href="https://docs.meteor.com/tutorials/blaze/" rel="noopener noreferrer"&gt;Meteor Blaze Guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Github Repo: &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kheAI" rel="noopener noreferrer"&gt;
        kheAI
      &lt;/a&gt; / &lt;a href="https://github.com/kheAI/todos-app" rel="noopener noreferrer"&gt;
        todos-app
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;📝 Simple Todos (Meteor 3 + Blaze)&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://meteor.com" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/574d72bd8a08784ad91e633e78721f9d2cbdde6337911fa99c4053b32095a9f6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d6574656f722d332e342e312d7265643f6c6f676f3d6d6574656f72" alt="Meteor Version"&gt;&lt;/a&gt;
&lt;a href="https://github.com/kheAI/todos-app#" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9de091cd711a25e148027ccf20487015ae6ee7fd63583a80a8c663a9d4b5c803/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f46726f6e74656e642d426c617a652d6f72616e6765" alt="Frontend"&gt;&lt;/a&gt;
&lt;a href="https://github.com/kheAI/todos-app#" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c32bbad0f07e58b78121062d527ed984e5ae89a221bfca692647890e6c86c8f1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f42756e646c65722d52737061636b2d79656c6c6f77" alt="Bundler"&gt;&lt;/a&gt;
&lt;a href="https://github.com/kheAI/todos-app#" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/88452814468c4f6d0a814b0c23ae02a80a13ba1a6353f67c09f4cdf822bc5bd5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4353532d5069636f4353532d626c7565" alt="CSS Framework"&gt;&lt;/a&gt;
&lt;a href="https://kheai-todo.sandbox.galaxycloud.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/86e871c690ba9150223d03ca0438f6e79117d26be5f6704c31f51961c5bff260/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4465706c6f7965642d4d6574656f725f47616c6178792d737563636573733f6c6f676f3d6d6574656f72" alt="Deployed on Galaxy"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A reactive, full-stack To-Do application built to demonstrate the power and speed of &lt;strong&gt;Meteor 3.4.1&lt;/strong&gt; using its native &lt;strong&gt;Blaze&lt;/strong&gt; templating engine.&lt;/p&gt;
&lt;p&gt;This project showcases modern Meteor features including &lt;code&gt;Rspack&lt;/code&gt; for lightning-fast bundling, fully asynchronous database operations (&lt;code&gt;Async/Await&lt;/code&gt;), user authentication, and Optimistic UI.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚀 Live Demo&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://kheai-todo.sandbox.galaxycloud.app/" rel="nofollow noopener noreferrer"&gt;Play with the live app here!&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;(Deployed via Meteor Galaxy)&lt;/em&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Reactivity:&lt;/strong&gt; Changes in the database are instantly reflected in the UI without manual DOM manipulation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimistic UI:&lt;/strong&gt; When a user checks or deletes a task, the UI updates instantly (zero latency) while the server processes the request securely in the background.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Authentication:&lt;/strong&gt; Built-in secure login system using &lt;code&gt;accounts-password&lt;/code&gt; and &lt;code&gt;bcrypt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Security:&lt;/strong&gt; Strict data-flow control using Meteor Publications/Subscriptions and secure Remote Procedure Calls (Meteor Methods).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Management:&lt;/strong&gt; Client-side state filtering (hiding completed tasks) managed via &lt;code&gt;reactive-dict&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Semantic Styling:&lt;/strong&gt; Zero-config, responsive…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kheAI/todos-app" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Aue-JcBxB3o"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Updated Full step-by-step Tutorial had been moved to &lt;a href="https://www.kheai.com/posts/6001-meteor-todo-tutorial-unofficial/" rel="noopener noreferrer"&gt;https://www.kheai.com/posts/6001-meteor-todo-tutorial-unofficial/&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You have just built a reactive, full-stack application with a real database, user authentication, and secure remote procedure calls. What you've learned here applies to applications of massive scale. Welcome to the Meteor ecosystem!&lt;/p&gt;

</description>
      <category>meteor</category>
      <category>kheai</category>
      <category>fullstack</category>
      <category>webdev</category>
    </item>
    <item>
      <title>HuntOS: The Autonomous Enterprise Sentinel — A Production-Grade Agentic Swarm on the Next '26 Stack</title>
      <dc:creator>Khe Ai</dc:creator>
      <pubDate>Sun, 26 Apr 2026 17:16:09 +0000</pubDate>
      <link>https://dev.to/kheai/huntos-the-autonomous-enterprise-sentinel-a-production-grade-agentic-swarm-on-the-next-26-stack-5h7</link>
      <guid>https://dev.to/kheai/huntos-the-autonomous-enterprise-sentinel-a-production-grade-agentic-swarm-on-the-next-26-stack-5h7</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://www.google.com/url?sa=E&amp;amp;q=https%3A%2F%2Fdev.to%2Fchallenges%2Fgoogle-cloud-next-2026-04-22"&gt;Google Cloud NEXT Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;The era of vibe-coding fragile chatbot prototypes is over. Thanks to extensive research into the announcements at &lt;a href="https://www.google.com/url?sa=E&amp;amp;q=https%3A%2F%2Fdev.to%2Fyeemun122%2Fthe-end-of-the-prototype-trap-real-engineering-lessons-from-google-cloud-next-26-347f"&gt;Google Cloud Next '26&lt;/a&gt;, I have combined the most impactful platform updates into one cohesive architecture. This project demonstrates the full &lt;strong&gt;Agentic Enterprise&lt;/strong&gt; stack in action—systems that don't just chat, but take verified, physical business actions.&lt;/p&gt;

&lt;p&gt;To pressure-test this new stack, I built &lt;strong&gt;HuntOS&lt;/strong&gt;: an autonomous, cross-cloud security swarm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/ai/260427-huntos-sentinel-dev_aUSGyGujt.png" rel="noopener noreferrer"&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%2Fo40p1guxdxeaedw9xod4.png" alt="HuntOS: The Autonomous Enterprise Sentinel. Building the First Production-Grade Agentic Swarm on the Next '26 Stack" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;HuntOS is an Agent-to-Agent (A2A) workforce designed to hunt anomalies across disconnected environments. It ingests messy unstructured "dark data" (like AWS S3 logs), cross-references anomalies against a secure Spanner Graph, and orchestrates a swarm of Gemini 3.1 Pro agents to draft, critique, and deploy Terraform remediation scripts. All with zero human intervention and enterprise-grade egress security.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Next '26 Equation:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;(Cross-Cloud Lakehouse × Knowledge Catalog) + MCP Server + (A2A Swarm @ TPU v8i) + (Agent Gateway + Model Armor) + Vertex AI Memory Bank = Production-Ready Agentic OS&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;💡 &lt;strong&gt;For the Enterprise CISO:&lt;/strong&gt; Currently, remediating a cross-cloud leak takes hours of human investigation, Jira tickets, and manual Terraform patching. HuntOS reduces Time-To-Remediate (TTR) from hours to under 3 seconds—without requiring you to move your raw AWS logs into Google Cloud, and without exposing your database credentials directly to an LLM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo &amp;amp; Code
&lt;/h2&gt;

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

&lt;p&gt;&lt;strong&gt;Source Code:&lt;/strong&gt; &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kheAI" rel="noopener noreferrer"&gt;
        kheAI
      &lt;/a&gt; / &lt;a href="https://github.com/kheAI/huntos" rel="noopener noreferrer"&gt;
        huntos
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;HuntOS: The Autonomous Enterprise Sentinel&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/ai/260427-huntos-sentinel-dev_aUSGyGujt.png" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8a1b6963548ea59d6ab2040671036a5d6d14279fd7c19d61b83419ce71c8ec99/68747470733a2f2f696b2e696d6167656b69742e696f2f6d6f6f70742f6b686561692f61692f3236303432372d68756e746f732d73656e74696e656c2d6465765f615553477947756a742e706e67" alt="HuntOS-Banner"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HuntOS&lt;/strong&gt; is an autonomous, cross-cloud security swarm built to demonstrate the full &lt;strong&gt;Agentic Enterprise&lt;/strong&gt; stack announced at Google Cloud Next '26.&lt;/p&gt;
&lt;p&gt;It transitions from simple "fragile chatbot prototypes" to "Agentic AI" by detecting anomalies in "dark data" (messy AWS S3 logs), verifying them via a secure Spanner Graph, and orchestrating a swarm of Gemini 3.1 Pro agents to draft, critique, and deploy Terraform remediation scripts. All with zero human intervention and enterprise-grade egress security.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Next '26 Mega-Product Equation&lt;/strong&gt;
(Cross-Cloud Lakehouse × Knowledge Catalog) + MCP Server + (A2A Swarm @ TPU v8i) + (Agent Gateway + Model Armor) + Vertex AI Memory Bank = Production-Ready Agentic OS&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚦 Architectural Breakdown Matrix&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;System Requirement&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Next '26 Execution Method&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Primary Technology&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Function (The Sentinel Value)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Gravity / Ingestion&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cross-Cloud Connectivity&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Cross-Cloud Lakehouse &amp;amp; Knowledge Catalog&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Indexes unstructured "dark data" (PDFs/Logs) in-place across AWS and GCP&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kheAI/huntos" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  The Architecture: Reversing the Prototype Trap
&lt;/h2&gt;

&lt;p&gt;To win in modern infrastructure, you have to architect for the system, not just the AI. AI cannot verify your identity or configure cross-cloud IAM roles. You must lay the physical groundwork first.&lt;/p&gt;

&lt;p&gt;Here is the architectural breakdown of how I wired the Next '26 stack together:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/ai/260427-huntos-dashboard_d09KMTNGV.png" rel="noopener noreferrer"&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%2Fs4tog2g16s299ufqk9d0.png" alt="huntos-dashboard" width="799" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/ai/260427-huntos-view-fix_59uSsTQyb.png" rel="noopener noreferrer"&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%2Fph43c15e9twf3s3urqgn.png" alt="huntos-view-fix" width="800" height="705"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Conquering Data Gravity: Cross-Cloud Lakehouse
&lt;/h3&gt;

&lt;p&gt;The biggest friction in enterprise AI is moving data. Instead of paying massive egress fees to pull AWS S3 security logs into GCP, HuntOS utilizes the new &lt;strong&gt;Cross-Cloud Lakehouse&lt;/strong&gt;. By leveraging Cross-Cloud Interconnect (CCI) combined with bi-directional federation via the Apache Iceberg REST Catalog, the system indexes the logs &lt;em&gt;in place&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Vertex AI Knowledge Catalog&lt;/strong&gt; sits on top, allowing our agents to read these "dark data" PDFs as if they were local, low-latency files.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Zero-Trust Data Access: The MCP Bridge
&lt;/h3&gt;

&lt;p&gt;AI agents need database access to verify threats, but handing raw SQL credentials to an LLM is a massive security risk. HuntOS implements the breakout open-source standard: the &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I deployed an MCP bridge pointing to a newly provisioned &lt;strong&gt;Spanner Graph&lt;/strong&gt; database (hunter-os-db). This creates a secure, abstracted interface so the agent can query the blast radius between flagged anomalies and impacted microservices &lt;em&gt;without&lt;/em&gt; ever seeing the raw schema or connection strings.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Autonomous Swarm &amp;amp; The "Skeptic Loop"
&lt;/h3&gt;

&lt;p&gt;The core logic was generated using Google AI Studio leveraging the new &lt;strong&gt;A2A Protocol&lt;/strong&gt;. HuntOS is not one monolithic prompt; it is a delegated hierarchy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Manager Agent:&lt;/strong&gt; Flags the AWS log anomaly using the Knowledge Catalog tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Researcher Agent:&lt;/strong&gt; Queries the Spanner Graph via MCP to map the blast radius.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architect Agent:&lt;/strong&gt; Drafts the raw Terraform remediation script.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Red Team "Skeptic" Agent:&lt;/strong&gt; A dedicated critique loop. Before finalizing code, this agent aggressively scans the Architect's output to eliminate hallucinations and fix downtime risks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is a look under the hood at how the Skeptic Loop enforces code safety in my Next.js API route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. Architect drafts the raw Terraform based on Spanner Graph verification&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;architectPrompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Context: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;verification&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; Draft Terraform remediation.`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;draft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gemini-3.1-pro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;architectPrompt&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// 2. The Skeptic Loop - Red Team critiques for downtime risks before returning&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;skepticPrompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Critique this Terraform for production downtime risks or race conditions. Rewrite safely: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;finalRevision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gemini-3.1-pro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;skepticPrompt&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;finalRevision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Only the verified code is passed to the Gateway&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Institutional Memory via Semantic Grounding
&lt;/h3&gt;

&lt;p&gt;To ensure the Architect Agent doesn't write generic, tutorial-level code, I grounded the swarm using the &lt;strong&gt;Vertex AI Memory Bank&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Memory Bank doesn't just act as a static file drive. It utilizes an LLM-driven background process to extract, compress, and consolidate facts into a long-term knowledge graph. By uploading my company's official security guidelines alongside my own GitHub repositories, the agent uses &lt;strong&gt;semantic search&lt;/strong&gt; to retrieve my specific "Pragmatic Developer" preferences. It writes like &lt;em&gt;me&lt;/em&gt;, preventing context-window bloat.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Hardware &amp;amp; Edge Egress Security
&lt;/h3&gt;

&lt;p&gt;To execute sub-100ms reasoning loops for the "Red Team" simulations, the swarm is routed through the &lt;strong&gt;TPU v8i&lt;/strong&gt; architecture running on highly-optimized Google Axion Arm-based CPUs.&lt;/p&gt;

&lt;p&gt;Finally, transition to production requires strict perimeter security. I wrapped the Cloud Run deployment in an &lt;strong&gt;Agent Gateway&lt;/strong&gt;, configured with a strict &lt;strong&gt;Egress Model Armor template&lt;/strong&gt;. For an autonomous swarm executing live Terraform patches, strictly defining the &lt;em&gt;Agent-to-Anywhere (Egress)&lt;/em&gt; guardrails is the ultimate safeguard. It sanitizes all outbound code, blocks prompt injections, and mathematically ensures no internal API keys are leaked during execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overcoming Engineering Challenges
&lt;/h2&gt;

&lt;p&gt;Building a genuinely autonomous system revealed a few hurdles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The "Infinite Loop" Threat:&lt;/strong&gt; Initially, A2A agents can get stuck endlessly debating a fix. Implementing strict token budgets and a definitive "Architect vs. Skeptic" hierarchy was necessary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resilient Infrastructure:&lt;/strong&gt; Since MCP client connections to gcloud rely on local environment credentials, I had to architect graceful fallbacks in the Next.js route.ts. This ensures the dashboard remains highly available even if the backend MCP proxy temporarily disconnects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React Hydration:&lt;/strong&gt; Handling real-time agent telemetry in Next.js required careful useEffect management to prevent React hydration mismatches caused by split-second timestamp differences between the server and the browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architectural Breakdown Matrix
&lt;/h2&gt;

&lt;p&gt;For a quick reference of the Next '26 tools utilized in this build:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;System Requirement&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Next '26 Solution&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Function (The Sentinel Value)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Gravity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cross-Cloud Lakehouse&lt;/td&gt;
&lt;td&gt;Indexes unstructured dark data (PDFs/Logs) in-place across AWS and GCP without costly data egress.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Secure Data Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MCP Server&lt;/td&gt;
&lt;td&gt;Abstracted interface for agents to query live databases without exposing raw credentials.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Relational Intelligence&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Spanner Graph (GQL)&lt;/td&gt;
&lt;td&gt;Maps complex relationships between anomalies and system dependencies to identify root causes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Agent Swarm Logic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A2A Protocol&lt;/td&gt;
&lt;td&gt;Orchestrates handoffs between specialized agents (Researcher → Architect → Skeptic).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inference &amp;amp; Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;TPU v8i (Boardfly)&lt;/td&gt;
&lt;td&gt;Powers sub-100ms reasoning loops, allowing the Skeptic agent to run without stalling the pipeline.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code Sanitization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Gateway &amp;amp; Model Armor&lt;/td&gt;
&lt;td&gt;Automated egress filter to sanitize LLM-generated code and block prompt injections.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Visual Architecture&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Nano Banana 2&lt;/td&gt;
&lt;td&gt;Enables the Architect to output Mermaid.js/PlantUML for executive-facing conceptual diagrams.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Institutional Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Vertex AI Memory Bank&lt;/td&gt;
&lt;td&gt;Enforces corporate security standards and brand voice by grounding outputs in past successful patches.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Payoff: Why This Matters
&lt;/h2&gt;

&lt;p&gt;For this challenge, I wanted to showcase depth, usefulness, and genuine insight into where Cloud is heading.&lt;/p&gt;

&lt;p&gt;We are no longer just wrapping LLMs in simple chat interfaces. By leaning entirely into the physical infrastructure and security announcements of Next '26—especially MCP, Spanner Graph, and Model Armor—&lt;strong&gt;HuntOS proves that the Agentic Enterprise isn't just a concept. It is ready to deploy today&lt;/strong&gt;. &lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>cloudnextchallenge</category>
      <category>googlecloud</category>
      <category>kheai</category>
    </item>
    <item>
      <title>Automated Intelligence Dev Bounty Scouter with OpenClaw, Gemini &amp; SearXNG in RPi</title>
      <dc:creator>Khe Ai</dc:creator>
      <pubDate>Wed, 22 Apr 2026 08:26:26 +0000</pubDate>
      <link>https://dev.to/kheai/automated-intelligence-dev-bounty-scouter-with-openclaw-gemini-searxng-in-rpi-2623</link>
      <guid>https://dev.to/kheai/automated-intelligence-dev-bounty-scouter-with-openclaw-gemini-searxng-in-rpi-2623</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/openclaw-2026-04-16"&gt;OpenClaw Challenge&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Following up on my previous exploration in &lt;a href="https://dev.to/kheai/self-healing-dev-bounty-hunter-with-openclaw-361c"&gt;Self-Healing Dev Bounty Hunter with OpenClaw&lt;/a&gt;, I realized that total AI autonomy can sometimes be a trap. If you let an agent run completely unchecked, you end up hoarding garbage data.&lt;/p&gt;

&lt;p&gt;To solve this, I expanded the architecture into an &lt;strong&gt;Automated Intelligence Dev Bounty Scouter&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;KheAi's &lt;a href="https://www.kheai.com/posts/ai-autonomy-trap-human-in-the-loop-dev-bounty-scouter" rel="noopener noreferrer"&gt;Dev Bounty Scouter&lt;/a&gt; is an automated, lightweight aggregator designed specifically for solo developers. It discovers remote, short-term, cash-prize coding competitions, open-source grants, and hackathons. To be clear: this isn't for bug bounty hunters looking for security exploits; it is built for creative makers seeking low-competition, high-reward opportunities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/ai/260422-bounty-scouter-dev-tech-tutorial_jLzpO4eOC.png" rel="noopener noreferrer"&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%2Fuz35i1cjiu9f47vgrbq7.png" alt="Bounty Scouter (Tech Tutorial)" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At its core, it relies on a &lt;strong&gt;"Digital Hermit" workflow&lt;/strong&gt;—a hybrid architecture balancing edge computing (Raspberry Pi) and serverless cloud infrastructure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;The Edge Worker (RPi 4B):&lt;/strong&gt; Runs OpenClaw as a background daemon alongside a localized SearXNG instance, powered by Gemini 3.1 Flash-Lite. It scrapes, parses, and writes to a local JSONL file.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Cloud Vault (Cloud Run + Meteor):&lt;/strong&gt; A curated dashboard backed by MongoDB Atlas (M0 Free Tier) utilizing Vector Search.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Human-in-the-Loop:&lt;/strong&gt; Before any data touches the cloud vault, I personally review the Pi's local JSONL output, acting as the ultimate anti-fragile quality assurance layer.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How I Used OpenClaw
&lt;/h2&gt;

&lt;p&gt;OpenClaw is the central orchestrator of this system, but using it on a resource-constrained device like a Raspberry Pi 4B against strict API rate limits required some heavy engineering.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Taming OpenClaw with a "State Machine" Prompt
&lt;/h3&gt;

&lt;p&gt;Gemini 3.1 Flash-Lite is incredibly efficient, but its free tier has a strict Rate Limit (15 RPM). OpenClaw’s default reasoning loops (Thought/Action/Observation) can easily chew through 15 requests in seconds if the agent hits a roadblock or retry loop.&lt;/p&gt;

&lt;p&gt;To prevent &lt;code&gt;429 Too Many Requests&lt;/code&gt; errors, I built a custom local skill (&lt;code&gt;skills/kheai-scout/skill.md&lt;/code&gt;) that acts as a "God Prompt." I forced OpenClaw to operate strictly as a &lt;strong&gt;State Machine&lt;/strong&gt;. By batching its thoughts and locking its execution order, the agent minimizes API round-trips:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# EXECUTION PROTOCOL (Strict State Machine)&lt;/span&gt;
Trigger: When commanded to "Run Kheai Scout". You must execute the following states in exact order. 

&lt;span class="gu"&gt;## STATE 1: [MEMORY SYNCHRONIZATION]&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Read &lt;span class="sb"&gt;`~/.openclaw/workspace/scout_findings.jsonl`&lt;/span&gt; to memorize existing URLs and prevent duplicates.

&lt;span class="gu"&gt;## STATE 2: [QUERY GENERATION &amp;amp; EXECUTION]&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Execute exactly 3 highly specific, niche search queries (e.g., "indie developer bounty", "open source grant application") using the SearXNG tool. 

&lt;span class="gu"&gt;## STATE 3: [SKEPTICAL ANALYSIS]&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Filter out news aggregators, press releases, or student-only hackathons. 

&lt;span class="gu"&gt;## STATE 4: [DATA STRUCTURING &amp;amp; APPENDING]&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Format surviving challenges as strict, single-line JSON objects.
&lt;span class="p"&gt;-&lt;/span&gt; APPEND to &lt;span class="sb"&gt;`scout_findings.jsonl`&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Bypassing Search Limits with SearXNG
&lt;/h3&gt;

&lt;p&gt;To give OpenClaw web-searching capabilities without racking up Google/Bing API bills, I deployed SearXNG locally via Docker on the Pi. I configured OpenClaw's Search Tool to point directly to &lt;code&gt;http://localhost:8080&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I had to explicitly enable the &lt;code&gt;- json&lt;/code&gt; format in SearXNG's &lt;code&gt;settings.yml&lt;/code&gt; so OpenClaw could seamlessly parse the payloads.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/ai/260422-openclaw-searxng-json-setup_X0Tcs22p0.png" rel="noopener noreferrer"&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%2Feg3yv0h3jc35x2mrgnjc.png" alt="openclaw-searxng-json-setup" width="800" height="762"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Human-to-Cloud Handoff
&lt;/h3&gt;

&lt;p&gt;Every morning at 04:00 AM, a cronjob triggers OpenClaw. By 09:00 AM, I review &lt;code&gt;scout_findings.jsonl&lt;/code&gt;. I click the links, assess the "vibes" and Terms &amp;amp; Conditions, and if the bounty is high-value, I manually log it into my Meteor-Blaze app hosted on Google Cloud Run.&lt;/p&gt;

&lt;p&gt;Upon saving, the Meteor app calls a cloud-based embedding model (Gemini Embedding 1, outputting 768 dimensions) to generate vector embeddings for the bounty's tech stack and strategy notes, saving it directly to MongoDB Atlas.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PS: &lt;strong&gt;The Step-by-Step Implementation Tutorial Guide: Zero to Hero&lt;/strong&gt; (includes the full &lt;strong&gt;God Prompt&lt;/strong&gt;) is available at the bottom.&lt;/em&gt;&lt;/p&gt;

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

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

&lt;p&gt;&lt;em&gt;(In the demo, you can see OpenClaw executing its state-machine logic, querying the local SearXNG instance and formatting the extracted hackathons into the local JSONL.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/ai/260422-openclaw-searxng-preview_Njx-ZQFDO.png" rel="noopener noreferrer"&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%2F1uz8zjbf8cz3tzzs6tw5.png" alt="openclaw-searxng-preview" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Building an AI workflow isn't just about stringing APIs together; it's about anticipating failure points. Here are my biggest takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rate Limits Dictate Architecture:&lt;/strong&gt; You can't just tell an agent to "go find bounties." Without the State Machine prompt architecture, OpenClaw would accidentally DDOS my own local SearXNG instance or crash into Gemini's 15 RPM wall.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protect Your Home IP:&lt;/strong&gt; Running an automated search scraper from a home IP in Malaysia triggered Google CAPTCHAs within days. I learned I had to explicitly enable the &lt;code&gt;limiter&lt;/code&gt; plugin in SearXNG (backed by Redis) and configure outbound proxy pools to throttle requests and protect my network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$0/Month Cloud Stacks are Viable (with caveats):&lt;/strong&gt; Google Cloud Run (1GB RAM, Session Affinity enabled for Meteor WebSockets) paired with MongoDB Atlas M0 is a powerhouse. However, M0 clusters limit you to 512MB storage and 3 vector indexes, and cause a 5-10 second cold start delay on the first load of the day. For a solo dev tool, this trade-off is absolutely worth the $0 price tag.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Total Automation is a Trap:&lt;/strong&gt; The biggest lesson was accepting that AI shouldn't do 100% of the work. By letting OpenClaw handle the unstructured chaos of the web and forcing myself to be the final curator, I ensure my database remains a pristine, high-signal vault of opportunity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step-by-Step Implementation: Zero to Hero
&lt;/h2&gt;

&lt;p&gt;If you want to build this yourself, here is the exact workflow to set up your own autonomous bounty scouter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 1: The Local Engine Room (Raspberry Pi 4B)
&lt;/h3&gt;

&lt;p&gt;We need to set up SearXNG and OpenClaw on your Pi securely, ensuring they don't corrupt your SSD or drain your RAM.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1.1: Deploying SearXNG (The Right Way)
&lt;/h4&gt;

&lt;p&gt;By running SearXNG via Docker, you completely bypass the API costs and rate limits of Google or Bing search APIs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/ai/260422-openclaw-searxng-docker-setup_dW3bxYx9R.png" rel="noopener noreferrer"&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%2F26pfpkmm8qbulrz0ke12.png" alt="openclaw-searxng-docker-setup" width="800" height="681"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of a fragile one-line Docker command, use &lt;code&gt;docker compose&lt;/code&gt; to ensure it restarts on Pi reboots and allows easy configuration file mapping.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a directory: &lt;code&gt;mkdir -p ~/kheai-scout/searxng &amp;amp;&amp;amp; cd ~/kheai-scout/searxng&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;   &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;searxng&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;searxng/searxng:latest&lt;/span&gt;
       &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;searxng&lt;/span&gt;
       &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:8080"&lt;/span&gt;
       &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./searxng-data:/etc/searxng&lt;/span&gt;
       &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SEARXNG_BASE_URL=http://localhost:8080/&lt;/span&gt;
         &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SEARXNG_SECRET_KEY=generate_a_random_string_here&lt;/span&gt;
       &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;You don't need to download the &lt;code&gt;SEARXNG_SECRET_KEY&lt;/code&gt; key from anywhere—you literally just need to create a random string of characters! SearXNG uses this secret key to encrypt session cookies and keep your instance secure.&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;docker compose up -d&lt;/code&gt;. This creates the &lt;code&gt;./searxng-data&lt;/code&gt; folder.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Critical JSON Fix:&lt;/strong&gt; Open &lt;code&gt;./searxng-data/settings.yml&lt;/code&gt; (via &lt;code&gt;sudo nano&lt;/code&gt;. Find the &lt;code&gt;search.formats&lt;/code&gt; section and ensure &lt;code&gt;- json&lt;/code&gt; is explicitly listed. Restart the container: &lt;code&gt;docker compose restart&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/ai/260422-openclaw-searxng-json-setup_X0Tcs22p0.png" rel="noopener noreferrer"&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%2Feg3yv0h3jc35x2mrgnjc.png" alt="openclaw-searxng-json-setup" width="800" height="762"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1.2: OpenClaw Initialization
&lt;/h4&gt;

&lt;p&gt;Ensure your OpenClaw environment is pointed to Gemini and SearXNG.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Set your environment variable: &lt;code&gt;export GEMINI_API_KEY="your_api_key"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; In OpenClaw's configuration, define your Search Tool to use &lt;code&gt;http://localhost:8080&lt;/code&gt; (or &lt;code&gt;127.0.0.1:8080&lt;/code&gt;) so the agent queries your private instance, not the public web.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/ai/260422-openclaw-searxng-search-provider-setup_dfu9WXUlg.png" rel="noopener noreferrer"&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%2F3519g675ix30o5u5cyzm.png" alt="openclaw-searxng-search-provider-setup" width="799" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 2: The Master Skill (The God Prompt)
&lt;/h3&gt;

&lt;p&gt;OpenClaw interprets complex prompts best when they are structured as a &lt;strong&gt;State Machine&lt;/strong&gt;. This prevents the agent from rushing to write data before checking existing files. Copy and paste to tell OpenClaw to create a new skill as &lt;code&gt;/kheai-scout/SKILL.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;I want to add a new local skill. Please create a directory named skills/kheai-scout and save the following instructions into a file named skill.md inside it. Then, initialize the JSONL file mentioned in the prompt.

&lt;span class="gh"&gt;# SYSTEM OVERVIEW&lt;/span&gt;
You are the "KheAi Global Scout," an elite, highly skeptical threat-intelligence agent specializing in developer bounties, hackathons, and open-source grants. Your runtime is a resource-constrained Raspberry Pi relying on a strictly rate-limited API (max 15 requests per minute). 

You MUST act methodically, preserve memory, minimize API round-trips by batching your thoughts, and absolutely avoid hallucination.

&lt;span class="gh"&gt;# CRITICAL CONSTRAINTS (MANDATORY)&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; RATE LIMIT DEFENSE: You must combine your reasoning (Thoughts) and Tool Actions into as few steps as possible. Do not get stuck in retry loops.
&lt;span class="p"&gt;2.&lt;/span&gt; NO HALLUCINATION: If a deadline, prize pool, or platform is not explicitly stated in the search snippets, map the value to "Unknown". Do not guess or infer dates.
&lt;span class="p"&gt;3.&lt;/span&gt; STRICT JSONL OUTPUT: When appending data, you must use valid JSON objects on a single line. DO NOT use CSV format.
&lt;span class="p"&gt;4.&lt;/span&gt; DEDUPLICATION: You MUST read the existing local database BEFORE searching to memorize existing URLs. You must never log a URL that is already in the database.
&lt;span class="p"&gt;5.&lt;/span&gt; SKEPTICISM: Ignore news articles, blog posts, and press releases. Only log actual application pages, official hackathon platforms, or direct grant portals.

&lt;span class="gh"&gt;# EXECUTION PROTOCOL (Strict State Machine)&lt;/span&gt;
Trigger: When commanded to "Run Kheai Scout". You must execute the following states in exact order. 

&lt;span class="gu"&gt;## STATE 1: [MEMORY SYNCHRONIZATION]&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Action: Use your file-reading tool to read &lt;span class="sb"&gt;`~/.openclaw/workspace/scout_findings.jsonl`&lt;/span&gt;.
&lt;span class="p"&gt;-&lt;/span&gt; Goal: Extract and memorize the &lt;span class="sb"&gt;`URL`&lt;/span&gt; fields of all previously discovered challenges. If the file is empty or missing, proceed with an empty memory. 

&lt;span class="gu"&gt;## STATE 2: [QUERY GENERATION &amp;amp; EXECUTION]&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Action: Select exactly 3 highly specific, niche search queries from the approved concepts below:
&lt;span class="p"&gt;  -&lt;/span&gt; "indie developer bounty"
&lt;span class="p"&gt;  -&lt;/span&gt; "open source grant application"
&lt;span class="p"&gt;  -&lt;/span&gt; "online dev challenges"
&lt;span class="p"&gt;  -&lt;/span&gt; "new hackathon platforms"
&lt;span class="p"&gt;  -&lt;/span&gt; "active developer bounties"
&lt;span class="p"&gt;  -&lt;/span&gt; "web3 grant programs"
&lt;span class="p"&gt;-&lt;/span&gt; Action: Execute these 3 queries simultaneously or sequentially using the &lt;span class="sb"&gt;`web_search`&lt;/span&gt; (SearXNG) tool. 

&lt;span class="gu"&gt;## STATE 3: [SKEPTICAL ANALYSIS]&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Action: Review the search snippets. 
&lt;span class="p"&gt;-&lt;/span&gt; Filter out and set "Unknown" status:
&lt;span class="p"&gt;  -&lt;/span&gt; Any URL that matches a URL memorized in STATE 1.
&lt;span class="p"&gt;  -&lt;/span&gt; Any URL pointing to a news aggregator, blog, or press release.
&lt;span class="p"&gt;  -&lt;/span&gt; Any challenge that explicitly states it is restricted to high school students or non-developers.

&lt;span class="gu"&gt;## STATE 4: [DATA STRUCTURING &amp;amp; APPENDING]&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Action: For each surviving, verified challenge, format the data EXACTLY as a single-line JSON object. CRITICAL: You must properly escape any internal double quotes within the JSON values (e.g., use &lt;span class="se"&gt;\"&lt;/span&gt; ) to ensure the JSONL string remains strictly valid.
&lt;span class="p"&gt;-&lt;/span&gt; Required Schema:
  &lt;span class="sb"&gt;`{"Challenge_Title": "Exact Name", "Status": "Incoming/Ongoing/Expired/Unknown", "Platform_Name": "Platform or Unknown", "Prize_USD": "Numeric value or null", "Start_Date": "YYYY-MM-DD or null", "End_Date": "YYYY-MM-DD or null", "Tags": ["tag1", "tag2"], "URL": "https://..."}`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Action: Use your file-editing tool to APPEND these JSONL strings to the bottom of &lt;span class="sb"&gt;`~/.openclaw/workspace/scout_findings.jsonl`&lt;/span&gt;. Ensure a newline separates each object. CRITICAL: You must ONLY APPEND data to the file. NEVER overwrite or delete existing contents.

&lt;span class="gu"&gt;## STATE 5: [SHUTDOWN]&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Action: Output a concise terminal summary: "Mission Complete. [X] new bounties appended. [Y] duplicates ignored." 
&lt;span class="p"&gt;-&lt;/span&gt; Action: Cleanly terminate the session. Do not ask for further instructions.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://ik.imagekit.io/moopt/kheai/ai/260422-openclaw-searxng-preview_Njx-ZQFDO.png" rel="noopener noreferrer"&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%2F1uz8zjbf8cz3tzzs6tw5.png" alt="openclaw-searxng-preview" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 3: The Trophy Room (Cloud Run &amp;amp; Mongo Atlas)
&lt;/h3&gt;

&lt;p&gt;Your Pi does the heavy lifting of parsing search results. Now, we prepare the cloud environment where you manually inject the highest-quality finds.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3.1: MongoDB Atlas (M0 Free Tier)
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt; Create an M0 cluster in MongoDB Atlas (ensure it is in a region close to your Cloud Run deployment to minimize latency).&lt;/li&gt;
&lt;li&gt; Navigate to &lt;strong&gt;Atlas Search&lt;/strong&gt; and create a &lt;strong&gt;Vector Search Index&lt;/strong&gt; on your &lt;code&gt;bounties&lt;/code&gt; collection. You will map a field called &lt;code&gt;embedding&lt;/code&gt; (an array of floats) to enable semantic search on your "Strategy Notes" and "Tech Stack" tags later.&lt;/li&gt;
&lt;li&gt; To ensure the vector search portion operates perfectly, I will use a &lt;a href="https://www.kheai.com/posts/mastering-gemini-api-2026#5-the-embedding-evolution-april-2026-update" rel="noopener noreferrer"&gt;cloud-based embedding model&lt;/a&gt; (Gemini Embedding 1) within the Meteor app. PS: Gemini's &lt;code&gt;text-embedding-004&lt;/code&gt; outputs 768 dimensions. This is perfectly fine, but avoid switching to massive 3000+ dimension models, as querying them on an M0 cluster can cause performance bottlenecks or timeout errors.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Step 3.2: Google Cloud Run (Meteor App Deployment)
&lt;/h4&gt;

&lt;p&gt;Meteor apps require specific configurations to run statelessly on serverless architecture.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Containerize your Meteor-Blaze App:&lt;/strong&gt; Use a multi-stage Dockerfile to build the Node bundle and expose port &lt;code&gt;8080&lt;/code&gt; (Cloud Run's default expected port).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Cloud Run Settings:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory:&lt;/strong&gt; 1GB (which still easily fits within Google Cloud Run's free tier quotas) is usually sufficient for a personal Blaze dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session Affinity:&lt;/strong&gt; Enable this in Cloud Run settings. Meteor relies heavily on sticky sessions for WebSockets/DDP to function properly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment Variables:&lt;/strong&gt; Pass your &lt;code&gt;MONGO_URL&lt;/code&gt; (from Atlas) and &lt;code&gt;ROOT_URL&lt;/code&gt; (your Cloud Run domain).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Phase 4: The Daily "Digital Hermit" Workflow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;04:00 AM:&lt;/strong&gt; Your RPi cronjob triggers the &lt;code&gt;/kheai-scout/SKILL.md&lt;/code&gt; in OpenClaw. It reads &lt;code&gt;/workspace/scout_findings.jsonl&lt;/code&gt;, queries SearXNG, parses the snippets using Gemini Flash-Lite, and appends fresh, deduplicated jsonl lines to the file. &lt;strong&gt;Enhancement:&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;Beyond just proxies, explicitly enable the &lt;code&gt;limiter&lt;/code&gt; plugin in your &lt;code&gt;searxng-data/settings.yml&lt;/code&gt;. This prevents OpenClaw from accidentally DDOSing your own local SearXNG instance if the agent gets caught in a retry loop. Without Redis, the limiter plugin either won't work or will be highly inefficient.&lt;/li&gt;
&lt;li&gt;To protect your home IP in Malaysia, you must throttle the outbound requests within SearXNG itself. You need to configure the &lt;code&gt;outbound&lt;/code&gt; section in your &lt;code&gt;searxng-data/settings.yml&lt;/code&gt; and consider adding a proxy pool, otherwise Google will throw CAPTCHAs at your Pi's IP within days.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;09:00 AM:&lt;/strong&gt; You open &lt;code&gt;scout_findings.jsonl&lt;/code&gt; on your local machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Human Filter:&lt;/strong&gt; You click the URLs. If a challenge has terrible terms and conditions or the "vibe" is wrong, you delete the line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Logging:&lt;/strong&gt; For the high-value targets, you open your Cloud Run Meteor app, fill in the "Submit Challenge" form, and hit save. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Brain Sync:&lt;/strong&gt; Upon saving, your Meteor server calls an embedding API (either Ollama locally or another free-tier cloud endpoint), generates the vector for the bounty, and saves it into Mongo Atlas.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This architecture is practically bulletproof. The Pi handles the unstructured chaos of the web, and your cloud database remains a pristine, highly curated, vector-searchable vault of opportunity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ClawCon Michigan&lt;/strong&gt;: We would love to, but we missed it!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Team Submissions&lt;/strong&gt;: &lt;a class="mentioned-user" href="https://dev.to/kheai"&gt;@kheai&lt;/a&gt; &lt;a class="mentioned-user" href="https://dev.to/yeemun122"&gt;@yeemun122&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>openclawchallenge</category>
      <category>openclaw</category>
      <category>kheai</category>
    </item>
  </channel>
</rss>
