<?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: Gabriele Di Maria</title>
    <description>The latest articles on DEV Community by Gabriele Di Maria (@gabriele_dimaria_f47e042).</description>
    <link>https://dev.to/gabriele_dimaria_f47e042</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%2F4143210%2F4e2afb05-3a65-4ecf-b6a3-f6b52b89d9ee.png</url>
      <title>DEV Community: Gabriele Di Maria</title>
      <link>https://dev.to/gabriele_dimaria_f47e042</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gabriele_dimaria_f47e042"/>
    <language>en</language>
    <item>
      <title>How I Built a Local AI Agent Stack for $0/month (Hermes + Windmill + NVIDIA + Groq)</title>
      <dc:creator>Gabriele Di Maria</dc:creator>
      <pubDate>Fri, 25 Sep 2026 16:00:28 +0000</pubDate>
      <link>https://dev.to/gabriele_dimaria_f47e042/how-i-built-a-local-ai-agent-stack-for-0month-hermes-windmill-nvidia-groq-1g3o</link>
      <guid>https://dev.to/gabriele_dimaria_f47e042/how-i-built-a-local-ai-agent-stack-for-0month-hermes-windmill-nvidia-groq-1g3o</guid>
      <description>&lt;h1&gt;
  
  
  How I Built a Local AI Agent Stack for $0/month (Hermes + Windmill + NVIDIA + Groq)
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Published: 2026-09-25 | ~2,200 words | 11 min read&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Exists
&lt;/h2&gt;

&lt;p&gt;I needed AI agents that could actually &lt;em&gt;do&lt;/em&gt; things — run code, call APIs, browse the web, write files — not just chat. Cloud APIs got expensive fast, rate-limited unpredictably, and locked me into someone else's infrastructure.&lt;/p&gt;

&lt;p&gt;So I built a local stack on my Windows machine (i7-8700K, 32GB RAM, RTX 3080). Total monthly cost: &lt;strong&gt;$0&lt;/strong&gt;. Everything runs locally or on free tiers.&lt;/p&gt;

&lt;p&gt;This article documents what actually works, what broke repeatedly, and the solutions that stuck.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stack (What's Actually Running)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐
│                      ORCHESTRATION                               │
│  Windmill (localhost:8000) — 3 containers                       │
│  - windmill-postgres, windmill-server, windmill-worker          │
│  - Workspace: admins, NO_AUTH=true (dev only)                   │
│  - 13 scripts deployed: 7 pillars + 4 automations + 1 reviewer  │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                      MODEL LAYER                                 │
│  Primary: nvidia/nemotron-3-super-120b-a12b                     │
│  Fallback 1: openai/gpt-oss-120b (Groq)                         │
│  Fallback 2: openai/gpt-oss-20b (Groq)                          │
│  Reviewer: nvidia/nemotron-3-ultra-550b-a55b (adversarial)      │
│                                                                  │
│  Local Proxy: 127.0.0.1:8001 (OpenAI-compatible)                │
│  - 10 NVIDIA API keys in rotation                               │
│  - 6-model cascade on failure                                   │
│  - Tool calling + SSE streaming support                         │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                      AGENT INTERFACE                             │
│  Hermes Agent (Nous Research) — Telegram + local CLI            │
│  - Configured with custom provider → local proxy                │
│  - Fallback providers: Groq (gpt-oss-120b → gpt-oss-20b)       │
│  - Auxiliary model DISABLED (caused rate loops)                 │
│  - Bot Mode: 3 bots configured on Ultra 550B (see below)        │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                      TOOLS &amp;amp; AUTOMATION                          │
│  Webwright (Playwright) — browser automation                    │
│  NVIDIA Reviewer — adversarial code review via Windmill         │
│  Edge-TTS — local voice synthesis (Microsoft, free)             │
│  FFmpeg — video assembly                                        │
│  Retry watcher — cron every 2 min, Telegram alerts              │
└─────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Model Layer: Getting Reliability from Free Tiers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Core Problem
&lt;/h3&gt;

&lt;p&gt;NVIDIA NIM free tier: 40 RPM. That's it. One agent loop can burn 10 requests in seconds. Groq free tier is generous but has different models. OpenRouter credits exhausted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution 1: 10-Key Rotation (&lt;code&gt;nvidia_key_rotation.py&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Simplified logic
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KeyRotator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&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;fails&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cooldown_until&lt;/span&gt;&lt;span class="sh"&gt;"&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cooldown_until&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;now&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;key&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;All keys in cooldown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;report_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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="nb"&gt;str&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="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cooldown_until&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;410&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;999&lt;/span&gt;  &lt;span class="c1"&gt;# permanent skip
&lt;/span&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&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="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: 429 errors become 30-second cooldowns instead of hard stops. Keys that return 401/403/410 (EOL models) are permanently skipped.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution 2: 6-Model Cascade (&lt;code&gt;nvidia_cascade.py&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;When a key works but the model fails (timeout, 500, bad output), cascade to the next model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ACTIVE_MODELS&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;nvidia/nemotron-3.5-lightning-30b-a3b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# fastest, good for simple
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai/gpt-oss-20b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                       &lt;span class="c1"&gt;# Groq fallback via proxy
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nvidia/nemotron-3-super-120b-a12b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# primary workhorse
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai/gpt-oss-120b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                      &lt;span class="c1"&gt;# Groq fallback via proxy
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;glm-5.2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                                  &lt;span class="c1"&gt;# backup
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nvidia/nemotron-3-ultra-550b-a55b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# heavy reasoning, reviewer
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each model tried in order. First success wins. Logs show which model actually responded.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution 3: Local Proxy with Tool Calling + SSE (&lt;code&gt;nvidia_proxy.py&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;This was the hardest part. Hermes sends tool calls; the proxy must forward them to NVIDIA and return &lt;code&gt;tool_calls&lt;/code&gt; in the response. Also must stream SSE chunks correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key fixes that took days:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Forward &lt;code&gt;tools&lt;/code&gt; parameter in request body to NVIDIA&lt;/li&gt;
&lt;li&gt;Parse NVIDIA's response: if &lt;code&gt;tool_calls&lt;/code&gt; present, return as-is (don't wrap in text)&lt;/li&gt;
&lt;li&gt;SSE: yield chunks with &lt;code&gt;data: {json}\n\n&lt;/code&gt;, end with &lt;code&gt;data: [DONE]\n\n&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Handle &lt;code&gt;finish_reason: tool_calls&lt;/code&gt; correctly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without these, Hermes either got empty streams or couldn't execute tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution 4: Groq Fallback in Hermes Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Hermes config.yaml (relevant section)&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nvidia/nemotron-3-super-120b-a12b"&lt;/span&gt;
&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;custom"&lt;/span&gt;
&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;base_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:8001/v1"&lt;/span&gt;
&lt;span class="na"&gt;fallback_providers&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;groq"&lt;/span&gt;
    &lt;span class="na"&gt;models&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;openai/gpt-oss-120b"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai/gpt-oss-20b"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behavior: if primary (proxy) fails, Hermes automatically retries on Groq. Next turn, it tries primary again.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Orchestration Layer: Windmill
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;Self-hosted, no cloud dependency&lt;/li&gt;
&lt;li&gt;Scripts as version-controlled Python files&lt;/li&gt;
&lt;li&gt;Built-in retries, approval gates, schedules&lt;/li&gt;
&lt;li&gt;Variables for secrets (API keys, tokens)&lt;/li&gt;
&lt;li&gt;UI for monitoring job runs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The 10-Pillar Attempt (7 Real, 3 Archived)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pillar&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Approval Gate (human-in-the-loop)&lt;/td&gt;
&lt;td&gt;✅ Working, tested end-to-end&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Alternative Supervision&lt;/td&gt;
&lt;td&gt;❌ Blocked — needs API keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Self-Healing&lt;/td&gt;
&lt;td&gt;📦 Archived — no Docker socket in Windmill CE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Resilience/Queue&lt;/td&gt;
&lt;td&gt;✅ Restored via API (job 01a0d246)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Watchdog/Resume&lt;/td&gt;
&lt;td&gt;📦 Archived — same as Pillar 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Cleanup/Mutex&lt;/td&gt;
&lt;td&gt;⚠️ Partial — cleanup paths wrong, mutex OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Sandbox&lt;/td&gt;
&lt;td&gt;⚠️ Partial — shell escape possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8, 9, 10&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;❌ Never deployed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Reality&lt;/strong&gt;: Only Pillars 1 and 4 are production-ready. The rest need Docker socket access (Windmill EE feature) or significant rework.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Windmill Actually Runs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;retry_watcher.py&lt;/code&gt; — cron every 2 min, checks failed jobs, retries, notifies Telegram&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nvidia_reviewer.py&lt;/code&gt; — adversarial code review (called via webhook or manually)&lt;/li&gt;
&lt;li&gt;Webhook &lt;code&gt;comando-gabriele&lt;/code&gt; — receives signed Telegram commands, executes terminal/file ops&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Agent Interface: Hermes Agent
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Configuration That Works
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ~/.config/hermes/config.yaml (key sections)&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nvidia/nemotron-3-super-120b-a12b"&lt;/span&gt;
&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;custom"&lt;/span&gt;
&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;base_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:8001/v1"&lt;/span&gt;
  &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not-needed"&lt;/span&gt;  &lt;span class="c1"&gt;# proxy handles auth&lt;/span&gt;

&lt;span class="na"&gt;fallback_providers&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;groq"&lt;/span&gt;
    &lt;span class="na"&gt;models&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;openai/gpt-oss-120b"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai/gpt-oss-20b"&lt;/span&gt;

&lt;span class="na"&gt;auxiliary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;title_generation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;  &lt;span class="c1"&gt;# critical: was causing rate loops&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bot Mode (Actually Configured)
&lt;/h3&gt;

&lt;p&gt;3 bots, all on &lt;code&gt;nvidia/nemotron-3-ultra-550b-a55b&lt;/code&gt; (strongest model via proxy):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@direttore&lt;/code&gt; — strategic coordinator, custom SOUL.md&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@analista&lt;/code&gt; — market/technical analysis, custom SOUL.md
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@critico&lt;/code&gt; — adversarial review, custom SOUL.md&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Group chat "Progetto ReportForge" completed 3 rounds, converged on positioning. Cron on @direttore runs every 24h.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitation&lt;/strong&gt;: Bots share the same proxy/key pool. Heavy concurrent use hits rate limits. Serial execution (max 3 rounds) mitigates this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Problems &amp;amp; Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Rate Limits → Proxy + Rotation + Cascade + Fallback
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt;: 429 errors killed agent loops. Manual key switching.&lt;br&gt;
&lt;strong&gt;After&lt;/strong&gt;: Automatic. 10 keys, 30s cooldown on 429, cascade across 6 models, Groq fallback. Uptime &amp;gt;99% on free tiers.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Hallucinations → NVIDIA Reviewer + Model 550B
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Nemotron-Super-120b hallucinates function signatures, file paths, config options when context grows.&lt;br&gt;
&lt;strong&gt;Fix&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep sessions short (one task per conversation)&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;/new&lt;/code&gt; frequently&lt;/li&gt;
&lt;li&gt;Run adversarial review on critical code via &lt;code&gt;nvidia_reviewer&lt;/code&gt; (Ultra 550B, temp 0.1)&lt;/li&gt;
&lt;li&gt;Reviewer prompt: "Find errors, risks, hidden assumptions. Don't be nice. Be concise."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Tool Calling Broken → Proxy Rewrite
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Proxy returned text instead of &lt;code&gt;tool_calls&lt;/code&gt;. Hermes waited forever.&lt;br&gt;
&lt;strong&gt;Fix&lt;/strong&gt;: Proxy now passes &lt;code&gt;tools&lt;/code&gt; param to NVIDIA, returns raw &lt;code&gt;tool_calls&lt;/code&gt; array. Verified with Hermes tool execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Empty Streams → SSE Implementation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: "Empty stream" errors. NVIDIA sends SSE; proxy wasn't forwarding chunks correctly.&lt;br&gt;
&lt;strong&gt;Fix&lt;/strong&gt;: Proper chunk parsing, &lt;code&gt;data:&lt;/code&gt; prefix, &lt;code&gt;[DONE]&lt;/code&gt; terminator. Hermes now receives stream correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Model EOL (410 Gone) → Active List Maintenance
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Burned&lt;/strong&gt;: &lt;code&gt;meta/llama-3.1-*&lt;/code&gt;, &lt;code&gt;meta/llama-3.3-*&lt;/code&gt; (Aug 26, 2026), &lt;code&gt;openai/gpt-oss-120b&lt;/code&gt; on NVIDIA (Sep 3, 2026).&lt;br&gt;
&lt;strong&gt;Process&lt;/strong&gt;: Before using any model, &lt;code&gt;curl&lt;/code&gt; test. 410 = remove from cascade. Current active list maintained in &lt;code&gt;nvidia_cascade.py&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. BOM in JSON → UTF-8 Without BOM
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: PowerShell &lt;code&gt;Out-File -Encoding UTF8&lt;/code&gt; adds BOM (EF BB BF). Python &lt;code&gt;json.loads&lt;/code&gt; fails silently.&lt;br&gt;
&lt;strong&gt;Fix&lt;/strong&gt;: Always write with &lt;code&gt;[System.IO.File]::WriteAllText($path, $content, $utf8NoBom)&lt;/code&gt; where &lt;code&gt;$utf8NoBom = New-Object System.Text.UTF8Encoding $false&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Windmill DB via psql → API Only
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Mistake&lt;/strong&gt;: Direct psql inserts. Windmill cache didn't refresh. Scripts invisible in UI.&lt;br&gt;
&lt;strong&gt;Rule&lt;/strong&gt;: Only official Windmill API (CLI or HTTP). If API fails, stop and ask.&lt;/p&gt;




&lt;h2&gt;
  
  
  Numbers That Are Real
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Verified&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NVIDIA API keys&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;code&gt;API_key.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Active models in cascade&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nvidia_cascade.py&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fallback models (Groq)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Hermes config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windmill containers&lt;/td&gt;
&lt;td&gt;3 healthy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker ps&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployed scripts&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;Windmill UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pillar 1 test&lt;/td&gt;
&lt;td&gt;PASS&lt;/td&gt;
&lt;td&gt;Job 01a0d0cf&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pillar 4 restored&lt;/td&gt;
&lt;td&gt;PASS&lt;/td&gt;
&lt;td&gt;Job 01a0d246&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NVIDIA Reviewer test&lt;/td&gt;
&lt;td&gt;PASS&lt;/td&gt;
&lt;td&gt;Found bug in &lt;code&gt;sum(a,b): return a-b&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Webwright + Reviewer integration&lt;/td&gt;
&lt;td&gt;PASS&lt;/td&gt;
&lt;td&gt;10 issues found in git-filter-branch script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monthly cost&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;No paid services used&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disk C: free&lt;/td&gt;
&lt;td&gt;36%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;df -h&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disk D: free&lt;/td&gt;
&lt;td&gt;35%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;df -h&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disk E: free&lt;/td&gt;
&lt;td&gt;66%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;df -h&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What Works Well
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Local proxy + key rotation&lt;/strong&gt; — transforms brittle free tier into reliable service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windmill for orchestration&lt;/strong&gt; — scripts as code, visible runs, retries built-in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hermes + custom provider&lt;/strong&gt; — full agent capability (tools, files, terminal) on local models&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NVIDIA Reviewer (Ultra 550B)&lt;/strong&gt; — catches real bugs, costs $0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webwright&lt;/strong&gt; — browser automation that LLMs can actually drive (writes Playwright code)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bot Mode&lt;/strong&gt; — multi-perspective analysis without human moderation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry watcher + Telegram&lt;/strong&gt; — self-healing for transient failures&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What Doesn't Work / Needs Work
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pillars 2, 3, 5, 7, 8, 9, 10&lt;/strong&gt; — mostly need Docker socket (EE) or redesign for CE&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sandbox isolation&lt;/strong&gt; — shell escape possible in current pillar 8&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hermes context overflow&lt;/strong&gt; — long sessions degrade quality; &lt;code&gt;/new&lt;/code&gt; required frequently&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrent bot usage&lt;/strong&gt; — shares key pool, hits rate limits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No schedules in Windmill&lt;/strong&gt; — 0 created, retry watcher is external cron&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CBAPI MCP&lt;/strong&gt; — package has no CLI entry point; REST API works but ClickBank-focused (not SaaS)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AgentFuse affiliation&lt;/strong&gt; — pending approval (24h), MCP ready to install&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What I'd Do Differently
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Decision&lt;/th&gt;
&lt;th&gt;Would Change To&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Started with 10-pillar design&lt;/td&gt;
&lt;td&gt;Start with 2-3 pillars that solve immediate pain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built custom proxy from scratch&lt;/td&gt;
&lt;td&gt;Use existing OpenAI-compatible proxy if one supported tool calling + SSE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Put all models on same key pool&lt;/td&gt;
&lt;td&gt;Separate key pools per model tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Used Windmill CE for self-healing&lt;/td&gt;
&lt;td&gt;Accept CE limits; build external watchers instead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tried to automate everything&lt;/td&gt;
&lt;td&gt;Keep human-in-the-loop (Pillar 1) for critical gates&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Operational Checklist: Replicate This Stack
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Hardware&lt;/strong&gt;: Any machine with 16GB+ RAM, decent CPU. GPU optional (NIM runs on CPU).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Desktop&lt;/strong&gt; → WSL2 backend → &lt;code&gt;docker-compose up&lt;/code&gt; for Windmill&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NVIDIA API keys&lt;/strong&gt; → 10 free keys from &lt;code&gt;build.nvidia.com&lt;/code&gt; → &lt;code&gt;API_key.txt&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proxy&lt;/strong&gt; → &lt;code&gt;nvidia_proxy.py&lt;/code&gt; on 127.0.0.1:8001 (tool calling + SSE)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rotation&lt;/strong&gt; → &lt;code&gt;nvidia_key_rotation.py&lt;/code&gt; + &lt;code&gt;nvidia_cascade.py&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hermes&lt;/strong&gt; → Configure custom provider → proxy URL, add Groq fallbacks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windmill Variables&lt;/strong&gt; → Store Telegram token, NVIDIA reviewer key as secrets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webwright&lt;/strong&gt; → &lt;code&gt;pip install webwright&lt;/code&gt; → skill for Hermes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NVIDIA Reviewer&lt;/strong&gt; → Windmill script calling NIM Ultra 550B with adversarial prompt&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry watcher&lt;/strong&gt; → Windows Task Scheduler or cron → Telegram alerts&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AgentFuse affiliation&lt;/strong&gt; — if approved, install MCP, generate tracked links for SaaS tools developers actually use (Cursor, Vercel, Beehiiv, ConvertKit, Linear, PostHog)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dev.to article&lt;/strong&gt; — this one, published honestly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Micro-tool packaging&lt;/strong&gt; — ReportForge (GitHub/Jira weekly reports) ready for Gumroad at €29/€39&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Video engine&lt;/strong&gt; — same stack, packaged as CLI (faceless video automation)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplify pillars&lt;/strong&gt; — archive unused, harden the 2 that work&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Windmill&lt;/strong&gt;: &lt;a href="https://windmill.dev" rel="noopener noreferrer"&gt;https://windmill.dev&lt;/a&gt; (self-hosted docs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hermes Agent&lt;/strong&gt;: &lt;a href="https://hermes-agent.nousresearch.com" rel="noopener noreferrer"&gt;https://hermes-agent.nousresearch.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NVIDIA NIM&lt;/strong&gt;: &lt;a href="https://build.nvidia.com" rel="noopener noreferrer"&gt;https://build.nvidia.com&lt;/a&gt; (free tier: 40 RPM)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Groq&lt;/strong&gt;: &lt;a href="https://console.groq.com" rel="noopener noreferrer"&gt;https://console.groq.com&lt;/a&gt; (free tier: generous)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webwright&lt;/strong&gt;: &lt;a href="https://github.com/microsoft/webwright" rel="noopener noreferrer"&gt;https://github.com/microsoft/webwright&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edge-TTS&lt;/strong&gt;: &lt;code&gt;pip install edge-tts&lt;/code&gt; (Microsoft, free)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;This stack exists because I refused to pay $500+/month for agent infrastructure that randomly rate-limits or changes APIs. It's not magic — it's plumbing. Lots of plumbing. But it works, it's mine, and it costs nothing.&lt;/p&gt;

&lt;p&gt;If you build something similar: &lt;strong&gt;test every model before trusting it&lt;/strong&gt;, &lt;strong&gt;log every fallback&lt;/strong&gt;, and &lt;strong&gt;keep sessions short&lt;/strong&gt;. The free tiers are generous but unforgiving.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built on Windows 11, Docker Desktop, WSL2. Zero cloud dependencies. Zero subscriptions.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Discuss on &lt;a href="https://dev.to"&gt;Dev.to&lt;/a&gt; | &lt;a href="https://github.com" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://t.me" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>selfhosted</category>
      <category>python</category>
    </item>
  </channel>
</rss>
