<?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: Minkyu</title>
    <description>The latest articles on DEV Community by Minkyu (@minkyuthebuilder).</description>
    <link>https://dev.to/minkyuthebuilder</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3906100%2F0a42741d-29e7-4651-ae54-2f9f60682066.jpg</url>
      <title>DEV Community: Minkyu</title>
      <link>https://dev.to/minkyuthebuilder</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/minkyuthebuilder"/>
    <language>en</language>
    <item>
      <title>How I ran 6 LLMs in parallel without paying a cent in API fees (Electron + DOM Injection)</title>
      <dc:creator>Minkyu</dc:creator>
      <pubDate>Thu, 30 Apr 2026 12:28:01 +0000</pubDate>
      <link>https://dev.to/minkyuthebuilder/how-i-ran-6-llms-in-parallel-without-paying-a-cent-in-api-fees-electron-dom-injection-2819</link>
      <guid>https://dev.to/minkyuthebuilder/how-i-ran-6-llms-in-parallel-without-paying-a-cent-in-api-fees-electron-dom-injection-2819</guid>
      <description>&lt;p&gt;Let’s be honest: trusting a single LLM with a complex problem is basically a coin toss right now.&lt;/p&gt;

&lt;p&gt;I got incredibly tired of my daily workflow: ask ChatGPT a question -&amp;gt; get a confident answer -&amp;gt; paste the same question into Claude to fact-check -&amp;gt; get a contradictory answer -&amp;gt; ask Perplexity to break the tie. I was acting as the manual API router, and it was exhausting.&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%2Fr0qxtaq29pvre2j9vxti.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%2Fr0qxtaq29pvre2j9vxti.png" alt=" " width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wanted a "Peer Review" system where the AIs cross-checked each other. But I quickly ran into two massive roadblocks:&lt;/p&gt;

&lt;p&gt;Cost: Running a 6-model cross-validation loop via official APIs (GPT-4o, Claude 3.5, deepseek, etc.) for every single query gets expensive fast.&lt;/p&gt;

&lt;p&gt;Latency (The Waterfall): Chaining these sequentially means waiting minutes for an answer.&lt;/p&gt;

&lt;p&gt;So, I decided to build AI Council — a local desktop app that bypasses APIs entirely and runs 6 AIs in parallel using their free web UIs. Here is how I built the orchestration logic without it turning into a complete disaster.&lt;/p&gt;

&lt;p&gt;The Architecture: Electron &amp;amp; 6 BrowserViews&lt;br&gt;
Instead of using standard REST API calls, the app is an Electron wrapper. It spins up 6 hidden (or visible, if you want the matrix vibe) BrowserView instances, loading the actual web interfaces of ChatGPT, Claude, Gemini, Perplexity, DeepSeek, and Grok.&lt;/p&gt;

&lt;p&gt;The entire "API" is just DOM injection: parsing the HTML, finding the text area, simulating keystrokes, and clicking the "Send" button.&lt;/p&gt;

&lt;p&gt;Bypassing the Waterfall: Fan-Out / Fan-In&lt;br&gt;
If Model A waits for Model B, and Model B waits for Model C, the UX is dead. To solve this, I used a Fan-out/Fan-in orchestration approach.&lt;/p&gt;

&lt;p&gt;Here is the flow:&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%2Fkijp8zno96b7atgzl5hj.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%2Fkijp8zno96b7atgzl5hj.png" alt=" " width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Primary Draft: You ask a question. The Primary AI (e.g., ChatGPT) generates a first draft.&lt;/p&gt;

&lt;p&gt;Fan-Out (Parallel Review): The app takes that draft and broadcasts it to the other 5 AI panels at the exact same time. It hits the "submit" button on all 5 BrowserViews simultaneously.&lt;/p&gt;

&lt;p&gt;Fan-In (Compilation): The app monitors the DOM of all 5 windows. Once they all stop generating, it extracts the text, compiles the feedback, and feeds it back to the Primary AI.&lt;/p&gt;

&lt;p&gt;The Final Output: The Primary AI rewrites the answer based on the peer review.&lt;/p&gt;

&lt;p&gt;Basically, the orchestration is just a giant, glorious Promise.allSettled.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Conceptual Fan-out logic&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;runParallelReview&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reviewers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;claudeView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;geminiView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;deepseekView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;grokView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;perplexityView&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// Fire them all at once&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reviewPromises&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reviewers&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;view&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="nf"&gt;injectPromptAndWaitForCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`Review this draft: &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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Wait for all models to finish physically typing&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reviews&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allSettled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reviewPromises&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;compileReviews&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reviews&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;The Real Headache: Managing Web UI States&lt;br&gt;
The hardest part wasn't the orchestration; it was dealing with the fact that web UIs change, and models stream text at different speeds.&lt;/p&gt;

&lt;p&gt;How do you know when an AI is "done" typing when you don't have a clean API response?&lt;br&gt;
You have to monitor the DOM state. For example, looking for the "Stop generating" button to disappear, or using a MutationObserver to watch the chat container. If "Grok's UI is being weird today," the whole promise chain could hang. I had to build robust timeout and fallback mechanisms for each specific wrapper so that one failing UI doesn't crash the entire council.&lt;/p&gt;

&lt;p&gt;The Result&lt;br&gt;
What I ended up with is a fully local, open-source app that gives me stress-tested, peer-reviewed answers. I even hooked it up to a local Telegram long-polling script, so I can text my council from my phone, my PC runs the BrowserViews, and it texts me the final consensus back. Zero cloud servers.&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%2Feqs3fgtbom1qrdr2amud.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%2Feqs3fgtbom1qrdr2amud.png" alt=" " width="800" height="529"&gt;&lt;/a&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%2F5tiq9s0vyo4i9t8dhfz3.jpg" 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%2F5tiq9s0vyo4i9t8dhfz3.jpg" alt=" " width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are curious about the DOM injection scripts or the Electron multi-view architecture, the entire project is open-source.&lt;/p&gt;

&lt;p&gt;Check out the repo here: 👉 &lt;a href="https://github.com/MinkyuTheBuilder/ai-council" rel="noopener noreferrer"&gt;https://github.com/MinkyuTheBuilder/ai-council&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to fork it, star it, or tell me why my DOM-scraping logic is terrible in the issues! I'd love to connect with anyone else building local multi-agent setups.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>chatgpt</category>
      <category>claude</category>
    </item>
  </channel>
</rss>
