<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Lakshmi Sravya Vedantham</title>
    <description>The latest articles on Forem by Lakshmi Sravya Vedantham (@lakshmisravyavedantham).</description>
    <link>https://forem.com/lakshmisravyavedantham</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%2F3783035%2F061c2d83-84c2-4fe4-886d-1977de27d4f3.jpeg</url>
      <title>Forem: Lakshmi Sravya Vedantham</title>
      <link>https://forem.com/lakshmisravyavedantham</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/lakshmisravyavedantham"/>
    <language>en</language>
    <item>
      <title>I Built a Skill So Claude Automatically Routes Tasks to Free-Tier AI Providers</title>
      <dc:creator>Lakshmi Sravya Vedantham</dc:creator>
      <pubDate>Fri, 27 Mar 2026 20:45:03 +0000</pubDate>
      <link>https://forem.com/lakshmisravyavedantham/i-built-a-skill-so-claude-automatically-routes-tasks-to-free-tier-ai-providers-1m10</link>
      <guid>https://forem.com/lakshmisravyavedantham/i-built-a-skill-so-claude-automatically-routes-tasks-to-free-tier-ai-providers-1m10</guid>
      <description>&lt;h1&gt;
  
  
  I Built a Skill So Claude Automatically Routes Tasks to Free-Tier AI Providers
&lt;/h1&gt;

&lt;p&gt;Here's a problem I kept running into: I have free-tier access to Groq, OpenAI, Gemini, and MiniMax — but managing them manually is painful. Wrong tool for the job, accidentally burning through monthly limits, no visibility into what's been used.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://github.com/LakshmiSravyaVedantham/agent-hub" rel="noopener noreferrer"&gt;agent-hub&lt;/a&gt; to fix this. It's a Claude Code skill that makes Claude the orchestrator — every task is automatically classified, routed to the best provider, tracked against free limits, and shown in a live status bar.&lt;/p&gt;




&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Claude classifies every incoming message into a task type and routes it:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task Type&lt;/th&gt;
&lt;th&gt;Signals&lt;/th&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;code&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;write/fix/debug/refactor&lt;/td&gt;
&lt;td&gt;Codex (gpt-4o-mini)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;research&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;explain/summarize/compare&lt;/td&gt;
&lt;td&gt;Gemini (gemini-2.0-flash)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;creative&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;story/dialogue/narrative&lt;/td&gt;
&lt;td&gt;MiniMax&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fast&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;yes/no, quick lookups&lt;/td&gt;
&lt;td&gt;Groq&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;general&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;everything else&lt;/td&gt;
&lt;td&gt;Groq&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Classification happens before calling any API — &lt;code&gt;router.py&lt;/code&gt; checks token budgets in &lt;code&gt;usage.json&lt;/code&gt;, picks the best available provider, calls its API, and returns the response.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auto-fallback:&lt;/strong&gt; when a provider drops below 10% of its free tier, traffic automatically shifts to its fallback (Groq→Gemini, Codex→Groq, Gemini→MiniMax, MiniMax→Gemini).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hard stop:&lt;/strong&gt; if both primary and fallback are exhausted, the router surfaces it to the user and stops. No silent failures.&lt;/p&gt;




&lt;h2&gt;
  
  
  The status bar
&lt;/h2&gt;

&lt;p&gt;Every response starts with a live usage bar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[GROQ ●] Groq: 1,240/14,400 · Codex: 77/500 · Gemini: 108K/1M · MiniMax: 220K/1M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;●&lt;/code&gt; green — above 50% remaining&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;●&lt;/code&gt; yellow — 10–50% remaining&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;●&lt;/code&gt; red — below 10% (fallback active)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;○&lt;/code&gt; gray — exhausted&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The active provider appears first in brackets. All four counts are always shown.&lt;/p&gt;




&lt;h2&gt;
  
  
  Free tier limits
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Groq&lt;/td&gt;
&lt;td&gt;llama-3.3-70b-versatile&lt;/td&gt;
&lt;td&gt;14,400 req/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex&lt;/td&gt;
&lt;td&gt;gpt-4o-mini&lt;/td&gt;
&lt;td&gt;500 req/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini&lt;/td&gt;
&lt;td&gt;gemini-2.0-flash&lt;/td&gt;
&lt;td&gt;1M tokens/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MiniMax&lt;/td&gt;
&lt;td&gt;abab6.5s-chat&lt;/td&gt;
&lt;td&gt;1M tokens/month&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SKILL_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.claude/plugins/cache/claude-plugins-official/superpowers/5.0.5/skills/agent-hub"&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SKILL_DIR&lt;/span&gt;&lt;span class="s2"&gt;/tests"&lt;/span&gt;
curl &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SKILL_DIR&lt;/span&gt;&lt;span class="s2"&gt;/router.py"&lt;/span&gt; https://raw.githubusercontent.com/LakshmiSravyaVedantham/agent-hub/main/router.py
curl &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SKILL_DIR&lt;/span&gt;&lt;span class="s2"&gt;/SKILL.md"&lt;/span&gt; https://raw.githubusercontent.com/LakshmiSravyaVedantham/agent-hub/main/SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then set your keys:&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;ROUTER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SKILL_DIR&lt;/span&gt;&lt;span class="s2"&gt;/router.py"&lt;/span&gt;
python3 &lt;span class="nv"&gt;$ROUTER&lt;/span&gt; set-key groq gsk_...
python3 &lt;span class="nv"&gt;$ROUTER&lt;/span&gt; set-key codex sk-...
python3 &lt;span class="nv"&gt;$ROUTER&lt;/span&gt; set-key gemini AIza...
python3 &lt;span class="nv"&gt;$ROUTER&lt;/span&gt; set-key minimax ...
python3 &lt;span class="nv"&gt;$ROUTER&lt;/span&gt; set-key minimax-group-id ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keys are stored in &lt;code&gt;~/.claude/agent-hub/.env&lt;/code&gt; with &lt;code&gt;chmod 600&lt;/code&gt; — never in code or skill files.&lt;/p&gt;




&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;In any Claude Code session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;superpowers:agent-hub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude validates your keys, shows the initial token bar, and from that point every message is classified and routed automatically. You don't think about providers — Claude does.&lt;/p&gt;

&lt;p&gt;Or call &lt;code&gt;router.py&lt;/code&gt; directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nv"&gt;$ROUTER&lt;/span&gt; route &lt;span class="s2"&gt;"explain how transformers work"&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt; research
python3 &lt;span class="nv"&gt;$ROUTER&lt;/span&gt; status
python3 &lt;span class="nv"&gt;$ROUTER&lt;/span&gt; reset groq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Under the hood
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;router.py&lt;/code&gt; is ~530 lines of Python 3.8+, two dependencies (&lt;code&gt;requests&lt;/code&gt;, &lt;code&gt;python-dotenv&lt;/code&gt;), 61 tests. Auto-reset logic zeros daily counters at UTC midnight and monthly counters on the 1st. Atomic writes to &lt;code&gt;usage.json&lt;/code&gt; via &lt;code&gt;.tmp&lt;/code&gt; + rename — no partial writes.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Three-agent coordination&lt;/strong&gt; — tested with one session, curious how routing behaves when multiple agents compete for the same provider budget&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code hooks integration&lt;/strong&gt; — auto-register sessions via hooks so the status bar appears without manually invoking the skill&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File section locks&lt;/strong&gt; — paired with agent-comms for per-file, per-section coordination&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/LakshmiSravyaVedantham/agent-hub" rel="noopener noreferrer"&gt;LakshmiSravyaVedantham/agent-hub&lt;/a&gt; — Python 3.8+, MIT license.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Built a Coordination System for Multiple Claude AI Agents — So They Stop Overwriting Each Other</title>
      <dc:creator>Lakshmi Sravya Vedantham</dc:creator>
      <pubDate>Fri, 27 Mar 2026 19:17:58 +0000</pubDate>
      <link>https://forem.com/lakshmisravyavedantham/i-built-a-coordination-system-for-multiple-claude-ai-agents-so-they-stop-overwriting-each-other-448i</link>
      <guid>https://forem.com/lakshmisravyavedantham/i-built-a-coordination-system-for-multiple-claude-ai-agents-so-they-stop-overwriting-each-other-448i</guid>
      <description>&lt;h1&gt;
  
  
  I Built a Coordination System for Multiple Claude AI Agents — So They Stop Overwriting Each Other
&lt;/h1&gt;

&lt;p&gt;Here's a problem nobody talks about yet but everyone will hit as AI-assisted development scales up: &lt;strong&gt;what happens when two Claude agents are working in the same codebase at the same time?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They overwrite each other. Silently. No warnings, no errors — just lost work.&lt;/p&gt;

&lt;p&gt;I built a skill to fix this. It's called &lt;code&gt;agent-comms&lt;/code&gt;, and it gives Claude agents a shared communication channel so they can coordinate before conflicts happen.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;I've been running multiple Claude Code sessions simultaneously on a project — one handling frontend UI work, another fixing the backend pipeline. Both intelligent, both fast, both completely unaware the other exists.&lt;/p&gt;

&lt;p&gt;The result: one agent refactors a file, the other overwrites it ten seconds later with a different version. Neither agent knows. The work is gone.&lt;/p&gt;

&lt;p&gt;The root issue: &lt;strong&gt;Claude agents have no shared awareness&lt;/strong&gt;. Each terminal is its own isolated context. There's no built-in coordination layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: File-Based Agent Communication
&lt;/h2&gt;

&lt;p&gt;The only channel multiple Claude agents share is the &lt;strong&gt;filesystem&lt;/strong&gt;. So that's where I built the communication layer.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;agent-comms&lt;/code&gt; creates a &lt;code&gt;.agent-comms/&lt;/code&gt; directory in your project root with three JSON files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.agent-comms/
  registry.json       — who is active right now
  announcements.json  — what files each agent plans to edit (and why)
  messages.json       — direct agent-to-agent messages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Python script (&lt;code&gt;comms.py&lt;/code&gt;) handles all reads and writes — atomic, stale-safe, zero dependencies.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Protocol
&lt;/h2&gt;

&lt;p&gt;Every agent follows the same lifecycle:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Register
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nv"&gt;$COMMS&lt;/span&gt; register researchUI &lt;span class="s2"&gt;"building dashboard UI components"&lt;/span&gt;
python3 &lt;span class="nv"&gt;$COMMS&lt;/span&gt; register Worker1 &lt;span class="s2"&gt;"fixing backend data pipeline"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Announce upfront — before touching any file
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nv"&gt;$COMMS&lt;/span&gt; announce researchUI &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"src/lib/api.ts|adding stream endpoint"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"src/pages/dashboard.tsx|adding real-time chart"&lt;/span&gt;

python3 &lt;span class="nv"&gt;$COMMS&lt;/span&gt; announce Worker1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"src/lib/api.ts|fixing broken API call"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"src/pages/dashboard.tsx|removing hardcoded mock data"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Check for conflicts
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nv"&gt;$COMMS&lt;/span&gt; check-conflicts Worker1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CONFLICT: researchUI also needs src/lib/api.ts — their reason: adding stream endpoint
CONFLICT: researchUI also needs src/pages/dashboard.tsx — their reason: adding real-time chart component
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two conflicts detected. &lt;strong&gt;Before a single file was touched.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Negotiate
&lt;/h3&gt;

&lt;p&gt;Worker1 (the later announcer) initiates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nv"&gt;$COMMS&lt;/span&gt; send Worker1 researchUI &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"CONFLICT on api.ts — my change: fixing broken endpoint call on line 34. I should go first since it's a bug fix."&lt;/span&gt;

python3 &lt;span class="nv"&gt;$COMMS&lt;/span&gt; send Worker1 researchUI &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"CONFLICT on dashboard.tsx — removing 3 hardcoded mock arrays. Safe to do before your chart work. Suggest: I go first."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;researchUI reads and replies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nv"&gt;$COMMS&lt;/span&gt; read-messages researchUI
&lt;span class="c"&gt;# FROM [Worker1]: CONFLICT on api.ts...&lt;/span&gt;
&lt;span class="c"&gt;# FROM [Worker1]: CONFLICT on dashboard.tsx...&lt;/span&gt;

python3 &lt;span class="nv"&gt;$COMMS&lt;/span&gt; send researchUI Worker1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"Agreed — go first on both. I'll wait for your DONE broadcast."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Worker1 finishes and broadcasts
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nv"&gt;$COMMS&lt;/span&gt; &lt;span class="k"&gt;done &lt;/span&gt;Worker1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"src/backend/classifier.py"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"src/lib/api.ts"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"src/pages/dashboard.tsx"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. researchUI gets the all-clear
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nv"&gt;$COMMS&lt;/span&gt; read-messages researchUI
&lt;span class="c"&gt;# FROM [Worker1]: [DONE] Worker1 finished. Modified: src/lib/api.ts, src/pages/dashboard.tsx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;researchUI now knows exactly which files were modified and can proceed safely.&lt;/p&gt;




&lt;h2&gt;
  
  
  Full Terminal Output
&lt;/h2&gt;

&lt;p&gt;Here's the actual output from a real test run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== researchUI announces its files ===
[agent-comms] Announced 3 file(s) for 'researchUI'

=== Worker1 announces its files ===
[agent-comms] Announced 3 file(s) for 'Worker1'

=== researchUI checks for conflicts ===
CONFLICT: Worker1 also needs src/lib/api.ts — their reason: fixing broken API call
CONFLICT: Worker1 also needs src/pages/dashboard.tsx — their reason: removing hardcoded mock data

=== Worker1 negotiates ===
[agent-comms] Sent from 'Worker1' to 'researchUI'
[agent-comms] Sent from 'Worker1' to 'researchUI'

=== researchUI reads messages ===
  FROM [Worker1] @ 2026-03-27T19:14:27: CONFLICT on api.ts — fixing broken endpoint call on line 34. I should go first.
  FROM [Worker1] @ 2026-03-27T19:14:27: CONFLICT on dashboard.tsx — removing 3 hardcoded mocks. Suggest: I go first.

=== researchUI agrees ===
[agent-comms] Sent from 'researchUI' to 'Worker1'

=== Worker1 finishes ===
[agent-comms] 'Worker1' done. Broadcast sent to 1 agent(s).

=== researchUI gets the all-clear ===
  FROM [Worker1]: [DONE] Worker1 finished. Modified: src/backend/classifier.py, src/lib/api.ts, src/pages/dashboard.tsx

=== Final status ===
[agent-comms] Active agents: 1 | Unread messages: 0
  [researchUI] building dashboard UI components
    planned files: dashboard.tsx, Chart.tsx, api.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero overwrites. Zero lost work.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It's Designed as a Claude Code Skill
&lt;/h2&gt;

&lt;p&gt;The system ships as a &lt;code&gt;SKILL.md&lt;/code&gt; — a Claude Code skill file that instructs Claude to follow the agent lifecycle automatically. When you invoke &lt;code&gt;superpowers:agent-comms&lt;/code&gt; in a Claude Code session, Claude:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Runs &lt;code&gt;status&lt;/code&gt; to see who's active&lt;/li&gt;
&lt;li&gt;Auto-assigns itself a name (or asks you to rename it)&lt;/li&gt;
&lt;li&gt;Registers itself with its task description&lt;/li&gt;
&lt;li&gt;Before any edit session — announces files and checks conflicts&lt;/li&gt;
&lt;li&gt;If conflict detected — initiates or responds to negotiation&lt;/li&gt;
&lt;li&gt;Every ~10 tool calls — sends a heartbeat&lt;/li&gt;
&lt;li&gt;When done — deregisters and broadcasts to all other agents&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;SKILL.md&lt;/code&gt; protocol:&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="gu"&gt;## Step 2: Announce Upfront (BEFORE any file edit)&lt;/span&gt;

Before touching ANY file this session, list every file you plan to edit and why:

python3 $COMMS announce agent-N &lt;span class="err"&gt;\&lt;/span&gt;
  "path/to/file.ts|reason for editing"

Then immediately check for conflicts:
python3 $COMMS check-conflicts agent-N

If output is CLEAR → proceed.
If output contains CONFLICT → go to Step 3 (negotiation).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Design Decisions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why file-based?&lt;/strong&gt;&lt;br&gt;
Claude agents in different terminals share nothing except the filesystem. No sockets, no shared memory, no APIs between them. Files are the only viable channel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why upfront announcements instead of locks?&lt;/strong&gt;&lt;br&gt;
Locks only catch conflicts at the moment of editing — after you've already started work. Announcements catch them before any work begins, when the cost of changing course is zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why negotiation instead of blocking?&lt;/strong&gt;&lt;br&gt;
Blocking wastes time. Negotiation lets agents make intelligent decisions: "include my change," "I'll go first," or "let's split the file." The agents have context about what they need — use it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stale agent cleanup:&lt;/strong&gt;&lt;br&gt;
Agents that haven't sent a heartbeat in 5 minutes are auto-removed from the registry. If an agent crashes without deregistering, it won't block others indefinitely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project-scoped:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;.agent-comms/&lt;/code&gt; lives in the project root and is added to &lt;code&gt;.gitignore&lt;/code&gt; automatically. Coordination state doesn't belong in git history.&lt;/p&gt;


&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SKILL_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.claude/plugins/cache/claude-plugins-official/superpowers/5.0.5/skills/agent-comms"&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SKILL_DIR&lt;/span&gt;&lt;span class="s2"&gt;/tests"&lt;/span&gt;
curl &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SKILL_DIR&lt;/span&gt;&lt;span class="s2"&gt;/comms.py"&lt;/span&gt; https://raw.githubusercontent.com/LakshmiSravyaVedantham/agent-comms/main/comms.py
curl &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SKILL_DIR&lt;/span&gt;&lt;span class="s2"&gt;/SKILL.md"&lt;/span&gt; https://raw.githubusercontent.com/LakshmiSravyaVedantham/agent-comms/main/SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then in any Claude Code session working in a shared project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;superpowers:agent-comms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Tests
&lt;/h2&gt;

&lt;p&gt;19 tests covering the full lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; pytest tests/ &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;span class="c"&gt;# 19 passed in 1.83s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Three-agent coordination&lt;/strong&gt; — tested with 2, curious how negotiation chains work at 3+&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File section locks&lt;/strong&gt; — "I own lines 1–80 of this file, you take 81–160"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration with Claude Code hooks&lt;/strong&gt; — auto-register/deregister via session hooks&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  GitHub
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/LakshmiSravyaVedantham/agent-comms" rel="noopener noreferrer"&gt;github.com/LakshmiSravyaVedantham/agent-comms&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Python 3.8+, stdlib only, MIT license. Drop it into your superpowers skill directory and your agents start coordinating immediately.&lt;/p&gt;

&lt;p&gt;If you're running multiple Claude sessions simultaneously, this will save you from the silent overwrite problem sooner or later.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>python</category>
      <category>devtools</category>
    </item>
    <item>
      <title>I Built a Tool So Claude Code Can Use My Colab GPU</title>
      <dc:creator>Lakshmi Sravya Vedantham</dc:creator>
      <pubDate>Sat, 21 Mar 2026 00:25:49 +0000</pubDate>
      <link>https://forem.com/lakshmisravyavedantham/i-built-a-tool-so-claude-code-can-use-my-colab-gpu-4hoi</link>
      <guid>https://forem.com/lakshmisravyavedantham/i-built-a-tool-so-claude-code-can-use-my-colab-gpu-4hoi</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;I use Claude Code daily. It can read my files, run bash commands, edit code — but the moment I need GPU compute, I'm back to copy-pasting between my terminal and Google Colab like it's 2020.&lt;/p&gt;

&lt;p&gt;I was working on a Videogen. The image generation runs locally on my Mac, but the model needs a GPU. Every time I wanted to test an image-to-video model, I had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Colab&lt;/li&gt;
&lt;li&gt;Paste my code&lt;/li&gt;
&lt;li&gt;Run cells manually&lt;/li&gt;
&lt;li&gt;Copy results back&lt;/li&gt;
&lt;li&gt;Repeat 50 times&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So I built &lt;strong&gt;claude-colab&lt;/strong&gt; — a bridge that gives Claude Code direct GPU access through Google Colab.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Colab (T4/A100 GPU)                     Your Machine
┌────────────────────┐                 ┌─────────────────┐
│ Flask API          │◄── HTTPS ──────►│ CLI / MCP Server│
│ E2E Encrypted      │  (cloudflared)  │                 │
│ Bearer token auth  │                 │ Claude Code     │
└────────────────────┘                 │ gains GPU tools │
                                       └─────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Colab notebook&lt;/strong&gt; — Flask API + Cloudflare tunnel on the GPU&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLI&lt;/strong&gt; — &lt;code&gt;pip install claude-colab&lt;/code&gt;, human-friendly commands&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP server&lt;/strong&gt; — Claude Code sees GPU tools natively&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  3-Line Setup
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;claude-colab
&lt;span class="c"&gt;# Open the notebook in Colab, run all cells, copy the connection string&lt;/span&gt;
claude-colab connect cc://TOKEN:KEY@your-tunnel.trycloudflare.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Claude now has a GPU.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Claude Can Do
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude-colab status                    &lt;span class="c"&gt;# GPU info&lt;/span&gt;
claude-colab &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"nvidia-smi"&lt;/span&gt;         &lt;span class="c"&gt;# Run any command&lt;/span&gt;
claude-colab python &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"import torch; print(torch.cuda.get_device_name(0))"&lt;/span&gt;
claude-colab upload model.py /content/model.py
claude-colab download /content/results.csv ./results.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with the MCP server, Claude calls these as tools directly — no copy-paste, no browser tabs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Security Part
&lt;/h2&gt;

&lt;p&gt;I didn't want my code traveling through Cloudflare in plaintext. Every request and response body is encrypted with &lt;a href="https://cryptography.io/en/latest/fernet/" rel="noopener noreferrer"&gt;Fernet&lt;/a&gt; (AES-128-CBC + HMAC-SHA256) before it hits the tunnel.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Who&lt;/th&gt;
&lt;th&gt;Can see&lt;/th&gt;
&lt;th&gt;Cannot see&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cloudflare&lt;/td&gt;
&lt;td&gt;URL paths, timing&lt;/td&gt;
&lt;td&gt;Your code, data, results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google&lt;/td&gt;
&lt;td&gt;Everything on the VM&lt;/td&gt;
&lt;td&gt;Your local files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Random internet&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Everything&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The connection string carries both a bearer token (auth) and an encryption key (privacy). Three ways to connect so it never lands in your shell history:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude-colab connect cc://...          &lt;span class="c"&gt;# Direct&lt;/span&gt;
claude-colab connect                    &lt;span class="c"&gt;# Interactive prompt&lt;/span&gt;
pbpaste | claude-colab connect -        &lt;span class="c"&gt;# Pipe from clipboard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real Usage: Testing Video Models
&lt;/h2&gt;

&lt;p&gt;The reason I built this — I needed to test image-to-video models for StoryGen. With claude-colab connected to an A100, I asked Claude to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upload a FLUX-generated scene image&lt;/li&gt;
&lt;li&gt;Install diffusers + transformers&lt;/li&gt;
&lt;li&gt;Load Wan2.1-I2V-14B (14 billion parameters)&lt;/li&gt;
&lt;li&gt;Generate an animated clip&lt;/li&gt;
&lt;li&gt;Download the result&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All from one conversation. No browser. No manual steps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;claude-colab &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"nvidia-smi --query-gpu=name,memory.total --format=csv"&lt;/span&gt;
&lt;span class="go"&gt;NVIDIA A100-SXM4-80GB, 81920 MiB
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wan2.1-14B loaded in full fp16, generated 33 frames in 3 minutes. That's the kind of workflow that was impossible before.&lt;/p&gt;

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

&lt;p&gt;82 tests, 96% coverage, 6 source files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/claude_colab/
├── crypto.py       # Fernet E2E encryption
├── config.py       # URI parsing, secure config
├── client.py       # HTTP client (shared by CLI + MCP)
├── cli.py          # Click commands
└── mcp_server.py   # 5 MCP tools for Claude Code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entire local package has 4 dependencies: &lt;code&gt;click&lt;/code&gt;, &lt;code&gt;httpx&lt;/code&gt;, &lt;code&gt;cryptography&lt;/code&gt;, &lt;code&gt;mcp&lt;/code&gt;. No torch, no ML libs — those live on Colab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;claude-colab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repo: &lt;a href="https://github.com/LakshmiSravyaVedantham/claude-colab" rel="noopener noreferrer"&gt;github.com/LakshmiSravyaVedantham/claude-colab&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the notebook in Colab, run all cells, paste the connection string. Your AI coding agent now has a GPU.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>opensource</category>
      <category>gpu</category>
    </item>
    <item>
      <title>I Built a Tool to Control AI Coding Agents from My Phone</title>
      <dc:creator>Lakshmi Sravya Vedantham</dc:creator>
      <pubDate>Wed, 18 Mar 2026 18:30:06 +0000</pubDate>
      <link>https://forem.com/lakshmisravyavedantham/i-built-a-tool-to-control-ai-coding-agents-from-my-phone-2g2g</link>
      <guid>https://forem.com/lakshmisravyavedantham/i-built-a-tool-to-control-ai-coding-agents-from-my-phone-2g2g</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;You're on the couch, in a coffee shop, or just away from your desk. You have a list of coding tasks you want done. You have AI coding agents (Claude Code, Aider, Codex, Gemini CLI) installed on your machine. But you can't use them from your phone.&lt;/p&gt;

&lt;p&gt;What if you could just text your tasks from Discord and have multiple AI agents start working on them — each in its own terminal?&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Agentboard&lt;/strong&gt; — an open-source tool that lets you orchestrate multiple AI coding agents from your phone via Discord.&lt;/p&gt;

&lt;p&gt;You type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;team Alpha: Build a landing page for my portfolio
team Beta: Fix the auth bug in my API
team Gamma: Write tests for the payment module
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And on your Mac, three Terminal windows open — each running Claude (or Aider, Codex, Gemini, whatever you configure) working on its assigned task. In parallel.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You (Discord on phone)
    |
    v
Discord Bot (Python, runs on your machine)
    |
    +-- Team Alpha -&amp;gt; Terminal.app -&amp;gt; claude "Build landing page..."
    +-- Team Beta  -&amp;gt; Terminal.app -&amp;gt; claude "Fix auth bug..."
    +-- Team Gamma -&amp;gt; Terminal.app -&amp;gt; claude "Write tests..."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;You send a message in Discord with &lt;code&gt;team Name: task&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The bot parses your message&lt;/li&gt;
&lt;li&gt;Opens a real Terminal window per team&lt;/li&gt;
&lt;li&gt;Runs your AI coding CLI interactively&lt;/li&gt;
&lt;li&gt;Each team works independently, in parallel&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No API credits needed for the bot itself — it uses your existing Claude Code subscription (or whatever CLI you have installed).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pluggable Backend
&lt;/h2&gt;

&lt;p&gt;Agentboard isn't locked to one AI tool. It works with any CLI:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Backend&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude "task"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aider&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aider --message "task"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex CLI&lt;/td&gt;
&lt;td&gt;&lt;code&gt;codex "task"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini CLI&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gemini "task"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Goose&lt;/td&gt;
&lt;td&gt;&lt;code&gt;goose run "task"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Any CLI&lt;/td&gt;
&lt;td&gt;Configure in &lt;code&gt;agentboard.toml&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone&lt;/span&gt;
git clone https://github.com/LakshmiSravyaVedantham/agentboard
&lt;span class="nb"&gt;cd &lt;/span&gt;agentboard/discord-bot

&lt;span class="c"&gt;# Setup&lt;/span&gt;
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="c"&gt;# Add your Discord bot token to .env&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'DISCORD_BOT_TOKEN=your-token'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ../.env

&lt;span class="c"&gt;# Run&lt;/span&gt;
python bot.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in Discord:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;team Alpha: Build a hello world Python script
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Terminal window opens on your Mac with Claude working on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Discord Bot (2 minutes)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://discord.com/developers/applications" rel="noopener noreferrer"&gt;Discord Developer Portal&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;New Application -&amp;gt; name it "Agentboard"&lt;/li&gt;
&lt;li&gt;Bot tab -&amp;gt; Reset Token -&amp;gt; copy it&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Message Content Intent&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;OAuth2 -&amp;gt; URL Generator -&amp;gt; scope: &lt;code&gt;bot&lt;/code&gt; -&amp;gt; permissions: Send Messages, Manage Channels, Read Message History&lt;/li&gt;
&lt;li&gt;Open the generated URL -&amp;gt; add bot to your server&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What's Under the Hood
&lt;/h2&gt;

&lt;p&gt;Agentboard also includes a full Rust backend (for those who want it):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;17 unit tests&lt;/strong&gt; covering config, auth, team state machine, backend registry, orchestrator&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Axum server&lt;/strong&gt; with 12 API endpoints + WebSocket&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Svelte PWA&lt;/strong&gt; with dark glassmorphism UI (pairing screen, team dashboard, live terminal output)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JWT auth&lt;/strong&gt; with 6-digit pairing codes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pluggable backends&lt;/strong&gt; via TOML config&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graceful shutdown&lt;/strong&gt; — SIGTERM to all child processes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Rust server compiles to a single 7.2MB binary with the frontend embedded via &lt;code&gt;rust-embed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But honestly? The Discord bot is the killer feature. It's 150 lines of Python and it just works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commands
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You type&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;team Alpha: Build a landing page&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Opens Terminal with Claude working on it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;team Alpha: Fix auth in ~/myproject&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Opens Terminal in that directory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shows all active teams&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kill Alpha&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Kills a team&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;help&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shows all commands&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Pick Your Terminal
&lt;/h2&gt;

&lt;p&gt;When you send a task, the bot asks which AI coding tool to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Which terminal should I use?
1️⃣ Claude
2️⃣ Codex
3️⃣ Aider
4️⃣ Gemini
5️⃣ Goose
6️⃣ OpenCode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React with a number. Each team can use a different tool if you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Split Panes + Named Sessions
&lt;/h2&gt;

&lt;p&gt;Multiple teams open as &lt;strong&gt;split panes&lt;/strong&gt; in the same Terminal window — not separate windows cluttering your desktop. Each Claude session gets a &lt;strong&gt;named session&lt;/strong&gt; (visible in the title bar and &lt;code&gt;/resume&lt;/code&gt;), so you always know which team is which.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discord Channels Per Team
&lt;/h2&gt;

&lt;p&gt;Each team gets its own &lt;strong&gt;Discord channel&lt;/strong&gt; (&lt;code&gt;#team-alpha&lt;/code&gt;, &lt;code&gt;#team-beta&lt;/code&gt;). Output streams into the channel in real-time, so you can monitor progress from your phone without switching windows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Discord?
&lt;/h2&gt;

&lt;p&gt;I tried building a PWA first. It worked, but:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Localhost firewall issues on phones&lt;/li&gt;
&lt;li&gt;Safari blocks Web Speech API without HTTPS&lt;/li&gt;
&lt;li&gt;Another app to maintain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Discord just works. It's on your phone, it handles notifications, and your data stays in your private server. The bot is 150 lines of Python with zero infrastructure cost.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Claude Code's &lt;code&gt;--print&lt;/code&gt; flag uses API credits, not your subscription.&lt;/strong&gt; The interactive &lt;code&gt;claude&lt;/code&gt; command uses your subscription. Big difference when you're spawning multiple agents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multiple Discord bots can pile up.&lt;/strong&gt; When developing, always &lt;code&gt;pkill -9 -f bot.py&lt;/code&gt; before starting a new instance. I had 6 zombie bots responding to the same messages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The simplest approach wins.&lt;/strong&gt; I designed an elaborate Rust+Svelte+WebSocket+JWT system. The Discord bot that actually ships is 150 lines of Python that opens Terminal windows. Ship the simple thing.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/LakshmiSravyaVedantham/agentboard" rel="noopener noreferrer"&gt;github.com/LakshmiSravyaVedantham/agentboard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Star it if you find it useful. PRs welcome — especially for Linux/Windows terminal support.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Agentboard is open source (MIT). No telemetry, no cloud, no data leaves your machine.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>rust</category>
    </item>
    <item>
      <title>I Stopped Paying $30/month for Video Resizing. Here's the Open-Source Alternative.</title>
      <dc:creator>Lakshmi Sravya Vedantham</dc:creator>
      <pubDate>Mon, 16 Mar 2026 17:38:10 +0000</pubDate>
      <link>https://forem.com/lakshmisravyavedantham/i-stopped-paying-30month-for-video-resizing-heres-the-open-source-alternative-4mgc</link>
      <guid>https://forem.com/lakshmisravyavedantham/i-stopped-paying-30month-for-video-resizing-heres-the-open-source-alternative-4mgc</guid>
      <description>&lt;p&gt;Every social platform wants a different video size.&lt;/p&gt;

&lt;p&gt;TikTok wants 9:16. YouTube wants 16:9. Instagram wants 1:1 &lt;em&gt;and&lt;/em&gt; 4:5. Twitter wants 16:9 but at 720p. LinkedIn wants 16:9 but allows 10-minute videos.&lt;/p&gt;

&lt;p&gt;Cloud tools like OpusClip and Kapwing charge $15-30/month for what ffmpeg can do for free — if you know the 47 flags. I wrapped it all in one Rust command.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;You record a video. Now you need it on 8 platforms. Each platform has its own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Aspect ratio&lt;/li&gt;
&lt;li&gt;Resolution&lt;/li&gt;
&lt;li&gt;Maximum duration&lt;/li&gt;
&lt;li&gt;Bitrate sweet spot&lt;/li&gt;
&lt;li&gt;Codec preferences&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pay Kapwing/OpusClip&lt;/strong&gt; — $15-30/month, upload your video to their cloud, wait for processing, download 8 versions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write ffmpeg commands&lt;/strong&gt; — Free, but you're writing 50+ lines of flags per platform, debugging filter chains, and maintaining a shell script that breaks every time you add a platform&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google's AutoFlip&lt;/strong&gt; — Was open-source, now deprecated&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I built option 4.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;socialcut input.mp4 &lt;span class="nt"&gt;--platforms&lt;/span&gt; all &lt;span class="nt"&gt;-o&lt;/span&gt; output/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One command. Eight platform-optimized videos. Done.&lt;/p&gt;

&lt;p&gt;No cloud upload. No subscription. No account. Your video never leaves your machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Platform Presets
&lt;/h2&gt;

&lt;p&gt;socialcut ships with 8 platform presets, each tuned to that platform's requirements:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Resolution&lt;/th&gt;
&lt;th&gt;Max Duration&lt;/th&gt;
&lt;th&gt;Bitrate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TikTok&lt;/td&gt;
&lt;td&gt;9:16&lt;/td&gt;
&lt;td&gt;1080x1920&lt;/td&gt;
&lt;td&gt;180s&lt;/td&gt;
&lt;td&gt;6 Mbps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instagram Reel&lt;/td&gt;
&lt;td&gt;9:16&lt;/td&gt;
&lt;td&gt;1080x1920&lt;/td&gt;
&lt;td&gt;90s&lt;/td&gt;
&lt;td&gt;5 Mbps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instagram Square&lt;/td&gt;
&lt;td&gt;1:1&lt;/td&gt;
&lt;td&gt;1080x1080&lt;/td&gt;
&lt;td&gt;60s&lt;/td&gt;
&lt;td&gt;5 Mbps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instagram Post&lt;/td&gt;
&lt;td&gt;4:5&lt;/td&gt;
&lt;td&gt;1080x1350&lt;/td&gt;
&lt;td&gt;60s&lt;/td&gt;
&lt;td&gt;5 Mbps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YouTube&lt;/td&gt;
&lt;td&gt;16:9&lt;/td&gt;
&lt;td&gt;1920x1080&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;8 Mbps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YouTube Shorts&lt;/td&gt;
&lt;td&gt;9:16&lt;/td&gt;
&lt;td&gt;1080x1920&lt;/td&gt;
&lt;td&gt;60s&lt;/td&gt;
&lt;td&gt;6 Mbps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Twitter&lt;/td&gt;
&lt;td&gt;16:9&lt;/td&gt;
&lt;td&gt;1280x720&lt;/td&gt;
&lt;td&gt;140s&lt;/td&gt;
&lt;td&gt;5 Mbps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LinkedIn&lt;/td&gt;
&lt;td&gt;16:9&lt;/td&gt;
&lt;td&gt;1920x1080&lt;/td&gt;
&lt;td&gt;600s&lt;/td&gt;
&lt;td&gt;8 Mbps&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These aren't guesses. They're pulled from each platform's upload specs and encoding recommendations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Commands
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;All platforms at once:&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;socialcut input.mp4 &lt;span class="nt"&gt;--platforms&lt;/span&gt; all &lt;span class="nt"&gt;-o&lt;/span&gt; output/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Just the platforms you need:&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;socialcut input.mp4 &lt;span class="nt"&gt;--platforms&lt;/span&gt; tiktok,instagram-reel,youtube &lt;span class="nt"&gt;-o&lt;/span&gt; output/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Letterbox mode — preserve everything, add padding:&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;socialcut input.mp4 &lt;span class="nt"&gt;--platforms&lt;/span&gt; instagram-square &lt;span class="nt"&gt;--mode&lt;/span&gt; letterbox &lt;span class="nt"&gt;--bg-color&lt;/span&gt; &lt;span class="s2"&gt;"#1a1a2e"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; output/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Burn a caption into the video:&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;socialcut input.mp4 &lt;span class="nt"&gt;--platforms&lt;/span&gt; tiktok &lt;span class="nt"&gt;--caption&lt;/span&gt; &lt;span class="s2"&gt;"Check this out!"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; tiktok.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Low quality for quick previews:&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;socialcut input.mp4 &lt;span class="nt"&gt;--platforms&lt;/span&gt; all &lt;span class="nt"&gt;--quality&lt;/span&gt; low &lt;span class="nt"&gt;-o&lt;/span&gt; preview/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Max quality for the final export:&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;socialcut input.mp4 &lt;span class="nt"&gt;--platforms&lt;/span&gt; youtube &lt;span class="nt"&gt;--quality&lt;/span&gt; max &lt;span class="nt"&gt;-o&lt;/span&gt; final.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Three Crop Modes
&lt;/h2&gt;

&lt;p&gt;This is where socialcut earns its keep. Converting between aspect ratios is the hard part, and there are three ways to handle it:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. crop (default) — Fill the frame, cut the edges
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input 16:9           Output 9:16 (TikTok)
+----------------+   +------+
|    |      |    |   |      |
|    | KEEP |    | &amp;gt; |      |
|    |      |    |   |      |
+----------------+   +------+
     crop sides
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No black bars. The output fills the entire frame. You lose some edges, but the result looks native to the platform.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;--gravity&lt;/code&gt; to control which part of the frame survives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--gravity top       --gravity center     --gravity bottom
+----------+        +----------+         +----------+
| KEEP     |        |          |         |          |
|          |        | KEEP     |         |          |
+----------+        |          |         | KEEP     |
|          |        +----------+         |          |
|          |        |          |         +----------+
+----------+        +----------+         +----------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. letterbox — Preserve everything, add bars
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input 16:9           Output 1:1 (Instagram)
+----------------+   +----------+
|                |   |##########|
|                | &amp;gt; |  video   |
|                |   |##########|
+----------------+   +----------+
                      # = padding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing gets cropped. Black bars (or any color you choose) fill the empty space. Use this when every pixel matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. fit — Same as letterbox, clearer name
&lt;/h3&gt;

&lt;p&gt;When "letterbox" sounds too technical. Same behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quality Presets
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Preset&lt;/th&gt;
&lt;th&gt;Bitrate&lt;/th&gt;
&lt;th&gt;Audio&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;td&gt;50% of platform spec&lt;/td&gt;
&lt;td&gt;96 kbps&lt;/td&gt;
&lt;td&gt;Quick previews, testing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;75% of platform spec&lt;/td&gt;
&lt;td&gt;128 kbps&lt;/td&gt;
&lt;td&gt;Drafts, internal review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;high (default)&lt;/td&gt;
&lt;td&gt;100% of platform spec&lt;/td&gt;
&lt;td&gt;192 kbps&lt;/td&gt;
&lt;td&gt;Final exports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;max&lt;/td&gt;
&lt;td&gt;150% of platform spec&lt;/td&gt;
&lt;td&gt;256 kbps&lt;/td&gt;
&lt;td&gt;Maximum quality&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How It Compares
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;socialcut&lt;/th&gt;
&lt;th&gt;OpusClip&lt;/th&gt;
&lt;th&gt;Kapwing&lt;/th&gt;
&lt;th&gt;raw ffmpeg&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Price&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;$15-30/mo&lt;/td&gt;
&lt;td&gt;$16-24/mo&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Privacy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100% local&lt;/td&gt;
&lt;td&gt;Cloud upload&lt;/td&gt;
&lt;td&gt;Cloud upload&lt;/td&gt;
&lt;td&gt;100% local&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fast (local)&lt;/td&gt;
&lt;td&gt;Upload-dependent&lt;/td&gt;
&lt;td&gt;Upload-dependent&lt;/td&gt;
&lt;td&gt;Fast (local)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ease of use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One command&lt;/td&gt;
&lt;td&gt;Web UI&lt;/td&gt;
&lt;td&gt;Web UI&lt;/td&gt;
&lt;td&gt;50-line script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;All 8 platforms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One command&lt;/td&gt;
&lt;td&gt;Manual each&lt;/td&gt;
&lt;td&gt;Manual each&lt;/td&gt;
&lt;td&gt;One script each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Offline&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Caption burning&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Manual filter chain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Open source&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (but no presets)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The cloud tools have nicer UIs. But they also have your video on their servers, a monthly fee, and a dependency on their uptime.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Info Command
&lt;/h2&gt;

&lt;p&gt;Before you process anything, check what you're working with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;socialcut info input.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instant metadata: resolution, duration, codec, fps, bitrate. No processing, just ffprobe under the hood.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Privacy Angle
&lt;/h2&gt;

&lt;p&gt;Your video never leaves your machine. Period.&lt;/p&gt;

&lt;p&gt;No cloud upload. No "processing on our servers." No terms of service granting usage rights to your content. No wondering what happens to that unreleased video you're editing.&lt;/p&gt;

&lt;p&gt;socialcut shells out to ffmpeg on your local machine. That's it. If your internet goes down, socialcut still works.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CLI (clap) &amp;gt; probe (ffprobe) &amp;gt; processor (ffmpeg) &amp;gt; output files
                                      |
                                  platform presets
                                  quality presets
                                  crop calculation
                                  filter chain builder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five modules, each doing one thing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;platform.rs&lt;/strong&gt; — 8 platform presets with aspect ratios, resolutions, durations, bitrates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;probe.rs&lt;/strong&gt; — ffprobe wrapper for video metadata extraction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;processor.rs&lt;/strong&gt; — crop/letterbox math, ffmpeg filter chain builder&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;caption.rs&lt;/strong&gt; — drawtext filter construction with proper escaping&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;quality.rs&lt;/strong&gt; — bitrate multipliers and CRF values&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built in Rust. 71 tests passing. No C bindings to ffmpeg — it shells out, which means if ffmpeg works on your system, socialcut works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/LakshmiSravyaVedantham/socialcut.git
&lt;span class="nb"&gt;cd &lt;/span&gt;socialcut
cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Requires ffmpeg&lt;/span&gt;
&lt;span class="c"&gt;# macOS: brew install ffmpeg&lt;/span&gt;
&lt;span class="c"&gt;# Ubuntu: apt install ffmpeg&lt;/span&gt;

socialcut input.mp4 &lt;span class="nt"&gt;--platforms&lt;/span&gt; all &lt;span class="nt"&gt;-o&lt;/span&gt; output/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Star the repo if this saves you a subscription: &lt;a href="https://github.com/LakshmiSravyaVedantham/socialcut" rel="noopener noreferrer"&gt;github.com/LakshmiSravyaVedantham/socialcut&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Your video. Your machine. Your formats. No cloud required.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>video</category>
      <category>opensource</category>
      <category>socialmedia</category>
    </item>
    <item>
      <title>I Generate $50 Stock Videos With One Command. Here's the Open-Source Tool.</title>
      <dc:creator>Lakshmi Sravya Vedantham</dc:creator>
      <pubDate>Mon, 16 Mar 2026 17:37:43 +0000</pubDate>
      <link>https://forem.com/lakshmisravyavedantham/i-generate-50-stock-videos-with-one-command-heres-the-open-source-tool-1edh</link>
      <guid>https://forem.com/lakshmisravyavedantham/i-generate-50-stock-videos-with-one-command-heres-the-open-source-tool-1edh</guid>
      <description>&lt;p&gt;Stock footage sites charge $15–50 for a single looping background video.&lt;/p&gt;

&lt;p&gt;Gradient flows. Plasma effects. Aurora animations. The kind of stuff streamers use behind their webcam, designers drop into hero sections, and indie devs layer behind title screens.&lt;/p&gt;

&lt;p&gt;I got tired of paying for something a computer can generate from math. So I built &lt;strong&gt;loopkit&lt;/strong&gt; — a single Rust binary that generates perfectly seamless looping videos from the command line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;loopkit generate &lt;span class="nt"&gt;--preset&lt;/span&gt; plasma &lt;span class="nt"&gt;--duration&lt;/span&gt; 5 &lt;span class="nt"&gt;-o&lt;/span&gt; plasma_loop.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. One command. Full HD. Perfectly looping. Free.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;You need a looping background video. Your options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pay per clip&lt;/strong&gt; — Shutterstock, Adobe Stock, Envato. $15–50 each. Licensing restrictions. Watermarks until you pay.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn After Effects&lt;/strong&gt; — Steep learning curve for something that should be simple.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Processing/TouchDesigner&lt;/strong&gt; — Great tools, but heavy setup and a runtime to manage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find free clips on Pexels&lt;/strong&gt; — Limited selection, everyone uses the same ones.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these feel right for something that is, fundamentally, &lt;em&gt;math applied to pixels over time&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;loopkit ships as a single binary. No Python. No Node. No runtime. Install it, run one command, get an MP4.&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;# Install from source&lt;/span&gt;
git clone https://github.com/LakshmiSravyaVedantham/loopkit.git
&lt;span class="nb"&gt;cd &lt;/span&gt;loopkit
cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prerequisites: Rust 1.70+ and ffmpeg (for encoding).&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;# macOS&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;ffmpeg

&lt;span class="c"&gt;# Ubuntu/Debian&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;ffmpeg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5 Built-In Presets
&lt;/h2&gt;

&lt;p&gt;Every preset produces a different visual effect. All of them loop seamlessly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plasma
&lt;/h3&gt;

&lt;p&gt;Classic sine wave interference pattern with shifting rainbow hues. Think 90s demoscene.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;loopkit generate &lt;span class="nt"&gt;--preset&lt;/span&gt; plasma &lt;span class="nt"&gt;--duration&lt;/span&gt; 5 &lt;span class="nt"&gt;--fps&lt;/span&gt; 30 &lt;span class="nt"&gt;-o&lt;/span&gt; plasma.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Gradient
&lt;/h3&gt;

&lt;p&gt;Smooth flowing gradient that morphs between deep blues, purples, and roses. Clean and modern — perfect for hero section backgrounds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;loopkit generate &lt;span class="nt"&gt;--preset&lt;/span&gt; gradient &lt;span class="nt"&gt;--duration&lt;/span&gt; 8 &lt;span class="nt"&gt;--fps&lt;/span&gt; 24 &lt;span class="nt"&gt;-o&lt;/span&gt; gradient.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Aurora
&lt;/h3&gt;

&lt;p&gt;Northern lights simulation with swaying curtains of green and teal. Organic, atmospheric movement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;loopkit generate &lt;span class="nt"&gt;--preset&lt;/span&gt; aurora &lt;span class="nt"&gt;--duration&lt;/span&gt; 6 &lt;span class="nt"&gt;--fps&lt;/span&gt; 30 &lt;span class="nt"&gt;-o&lt;/span&gt; aurora.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Waves
&lt;/h3&gt;

&lt;p&gt;Layered ocean surface with blue/teal waves and white foam highlights. Calming and rhythmic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;loopkit generate &lt;span class="nt"&gt;--preset&lt;/span&gt; waves &lt;span class="nt"&gt;--duration&lt;/span&gt; 5 &lt;span class="nt"&gt;--fps&lt;/span&gt; 30 &lt;span class="nt"&gt;-o&lt;/span&gt; waves.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fire
&lt;/h3&gt;

&lt;p&gt;Turbulent fire and lava with orange, red, yellow palette and white-hot core. High energy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;loopkit generate &lt;span class="nt"&gt;--preset&lt;/span&gt; fire &lt;span class="nt"&gt;--duration&lt;/span&gt; 4 &lt;span class="nt"&gt;--fps&lt;/span&gt; 30 &lt;span class="nt"&gt;-o&lt;/span&gt; fire.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generate All At Once
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;preset &lt;span class="k"&gt;in &lt;/span&gt;plasma gradient aurora waves fire&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;loopkit generate &lt;span class="nt"&gt;--preset&lt;/span&gt; &lt;span class="nv"&gt;$preset&lt;/span&gt; &lt;span class="nt"&gt;--duration&lt;/span&gt; 5 &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;preset&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_loop.mp4"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How Seamless Loops Actually Work
&lt;/h2&gt;

&lt;p&gt;This is the key insight that makes loopkit possible.&lt;/p&gt;

&lt;p&gt;Most people try to make loops by blending the last few frames into the first few frames. Cross-fading. It works, but you can usually spot the seam — there's a subtle "pulse" where the blend happens.&lt;/p&gt;

&lt;p&gt;loopkit does something different: &lt;strong&gt;it never creates a seam in the first place.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of parameterizing time as a linear ramp (0 to 1), we parameterize it as an angle on a circle (0 to 2pi):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        cos=1
         |
         |
sin=-1 --+-- sin=1
         |
         |
        cos=-1

Frame 0 starts at angle 0 (top of circle)
Frame N ends at angle 2pi (back to top)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since &lt;code&gt;sin(0) = sin(2pi)&lt;/code&gt; and &lt;code&gt;cos(0) = cos(2pi)&lt;/code&gt;, the first frame and last frame are &lt;strong&gt;mathematically identical&lt;/strong&gt;. Not "close enough" — identical. Zero seam. Zero blend artifact.&lt;/p&gt;

&lt;p&gt;Here's the actual code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;phase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total_frames&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;PI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;phase&lt;/span&gt;&lt;span class="nf"&gt;.sin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// circular time component 1&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;phase&lt;/span&gt;&lt;span class="nf"&gt;.cos&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// circular time component 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every preset receives &lt;code&gt;t1&lt;/code&gt; and &lt;code&gt;t2&lt;/code&gt; as its time inputs. The pattern evolves through a complete cycle on the unit circle and returns exactly to its starting state.&lt;/p&gt;

&lt;p&gt;Each preset then combines these circular time parameters with spatial coordinates (pixel x, y) through layered sine and cosine functions to produce organic, evolving patterns.&lt;/p&gt;




&lt;h2&gt;
  
  
  Custom Resolution
&lt;/h2&gt;

&lt;p&gt;Need vertical video for TikTok or Instagram Reels? Just flip the dimensions:&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;# 1080x1920 vertical video&lt;/span&gt;
loopkit generate &lt;span class="nt"&gt;--preset&lt;/span&gt; gradient &lt;span class="nt"&gt;--duration&lt;/span&gt; 8 &lt;span class="nt"&gt;--width&lt;/span&gt; 1080 &lt;span class="nt"&gt;--height&lt;/span&gt; 1920 &lt;span class="nt"&gt;-o&lt;/span&gt; vertical.mp4

&lt;span class="c"&gt;# 4K for the big screen&lt;/span&gt;
loopkit generate &lt;span class="nt"&gt;--preset&lt;/span&gt; aurora &lt;span class="nt"&gt;--duration&lt;/span&gt; 10 &lt;span class="nt"&gt;--width&lt;/span&gt; 3840 &lt;span class="nt"&gt;--height&lt;/span&gt; 2160 &lt;span class="nt"&gt;-o&lt;/span&gt; aurora_4k.mp4

&lt;span class="c"&gt;# Quick 720p preview&lt;/span&gt;
loopkit generate &lt;span class="nt"&gt;--preset&lt;/span&gt; fire &lt;span class="nt"&gt;--duration&lt;/span&gt; 3 &lt;span class="nt"&gt;--width&lt;/span&gt; 1280 &lt;span class="nt"&gt;--height&lt;/span&gt; 720 &lt;span class="nt"&gt;-o&lt;/span&gt; preview.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
  main.rs          CLI entry point (clap)
  lib.rs           Public API
  color.rs         HSL-to-RGB conversion, color interpolation
  renderer.rs      Frame generation + ffmpeg encoding
  presets/
    mod.rs         Preset trait + registry
    plasma.rs      Sine wave interference
    gradient.rs    Flowing color gradients
    aurora.rs      Northern lights
    waves.rs       Ocean waves
    fire.rs        Fire/lava
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rendering pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parse CLI arguments with clap&lt;/li&gt;
&lt;li&gt;Look up the preset function from the registry&lt;/li&gt;
&lt;li&gt;For each frame: compute &lt;code&gt;t1&lt;/code&gt;, &lt;code&gt;t2&lt;/code&gt; from the circular phase, render every pixel&lt;/li&gt;
&lt;li&gt;Save frames as PNGs in a temp directory&lt;/li&gt;
&lt;li&gt;Shell out to ffmpeg to encode PNGs into an MP4&lt;/li&gt;
&lt;li&gt;Clean up the temp directory&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;16 tests. All passing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why Rust?
&lt;/h2&gt;

&lt;p&gt;I could have built this in Python with Pillow. I chose Rust for three reasons:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Single binary.&lt;/strong&gt; &lt;code&gt;cargo install&lt;/code&gt; and you're done. No virtualenv, no &lt;code&gt;pip install&lt;/code&gt;, no "which Python version do I need?" — just a binary in your PATH.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Speed.&lt;/strong&gt; A 5-second 1080p video at 30fps means 150 frames. Each frame is ~2 million pixels. That's 300 million pixel computations. Rust handles this without flinching. Try that in Python and go make coffee.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. No runtime.&lt;/strong&gt; The only external dependency is ffmpeg for the final encoding step. Everything else — frame generation, color math, preset logic — is compiled into the binary.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/LakshmiSravyaVedantham/loopkit.git
&lt;span class="nb"&gt;cd &lt;/span&gt;loopkit
cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
loopkit generate &lt;span class="nt"&gt;--preset&lt;/span&gt; plasma &lt;span class="nt"&gt;--duration&lt;/span&gt; 5 &lt;span class="nt"&gt;-o&lt;/span&gt; my_first_loop.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Star the repo if this is useful: &lt;a href="https://github.com/LakshmiSravyaVedantham/loopkit" rel="noopener noreferrer"&gt;github.com/LakshmiSravyaVedantham/loopkit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ideas for contributions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New presets (starfield, geometric patterns, noise landscapes)&lt;/li&gt;
&lt;li&gt;Parallel frame rendering with rayon&lt;/li&gt;
&lt;li&gt;Custom color palettes via CLI&lt;/li&gt;
&lt;li&gt;GIF output option&lt;/li&gt;
&lt;li&gt;Preview mode (single frame to PNG)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stock footage sites are charging $50 for math. Now you have the math for free.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>video</category>
      <category>opensource</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I Piped My Server Logs Into a Video and Found the Bug in 10 Seconds</title>
      <dc:creator>Lakshmi Sravya Vedantham</dc:creator>
      <pubDate>Mon, 16 Mar 2026 17:37:06 +0000</pubDate>
      <link>https://forem.com/lakshmisravyavedantham/i-piped-my-server-logs-into-a-video-and-found-the-bug-in-10-seconds-186c</link>
      <guid>https://forem.com/lakshmisravyavedantham/i-piped-my-server-logs-into-a-video-and-found-the-bug-in-10-seconds-186c</guid>
      <description>&lt;p&gt;What if you could &lt;em&gt;see&lt;/em&gt; your data instead of reading it?&lt;/p&gt;

&lt;p&gt;I was tailing an access log at 2 AM, trying to find a latency spike buried in 50,000 lines of text. Scrolling. Grep. More scrolling. Then I piped the same log into a tool I'd been building, and the spike jumped out of a heatmap video in ten seconds flat.&lt;/p&gt;

&lt;p&gt;That tool is &lt;a href="https://github.com/LakshmiSravyaVedantham/vizpipe" rel="noopener noreferrer"&gt;&lt;strong&gt;vizpipe&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Concept
&lt;/h2&gt;

&lt;p&gt;Unix pipes are the most powerful abstraction in computing. You can chain &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt;, &lt;code&gt;sort&lt;/code&gt;, &lt;code&gt;uniq&lt;/code&gt; — transforming data through a pipeline that reads left to right like a sentence.&lt;/p&gt;

&lt;p&gt;But pipes always end in &lt;strong&gt;text&lt;/strong&gt;. What if they ended in &lt;strong&gt;video&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;stdin | vizpipe → MP4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the entire idea. vizpipe reads numbers from stdin and renders them as an animated video. No browser. No JavaScript. No dashboard. No accounts. Just a pipe and an MP4 file.&lt;/p&gt;

&lt;h2&gt;
  
  
  5 Commands That Changed How I Look at Data
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Count to 50, watch it grow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;1 50 | vizpipe &lt;span class="nt"&gt;--mode&lt;/span&gt; bars &lt;span class="nt"&gt;-o&lt;/span&gt; bars.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each number becomes a bar. The video builds up frame by frame. You see the data &lt;em&gt;accumulate&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. CSV trend line
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;sales.csv | vizpipe &lt;span class="nt"&gt;--mode&lt;/span&gt; line &lt;span class="nt"&gt;--column&lt;/span&gt; 2 &lt;span class="nt"&gt;-o&lt;/span&gt; trend.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extract column 2 from a CSV and draw a self-animating line chart. The line draws itself as data flows in.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Log latency heatmap
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;access.log | vizpipe &lt;span class="nt"&gt;--mode&lt;/span&gt; heatmap &lt;span class="nt"&gt;--pattern&lt;/span&gt; &lt;span class="s1"&gt;'\\d+ms'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; latency.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Regex extracts millisecond values from log lines. The heatmap lights up — and you &lt;em&gt;see&lt;/em&gt; where the spikes cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Real-time ping monitoring
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping &lt;span class="nt"&gt;-c&lt;/span&gt; 20 google.com | vizpipe &lt;span class="nt"&gt;--mode&lt;/span&gt; gauge &lt;span class="nt"&gt;--pattern&lt;/span&gt; &lt;span class="s1"&gt;'time=(\\d+\\.?\\d*)'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; ping.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A circular gauge that responds to each ping result. Satisfying and immediately useful.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Random scatter
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;shuf&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; 1-100 &lt;span class="nt"&gt;-n&lt;/span&gt; 200 | vizpipe &lt;span class="nt"&gt;--mode&lt;/span&gt; scatter &lt;span class="nt"&gt;-o&lt;/span&gt; random.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;200 random points appearing one by one on a 2D plane. Simple but hypnotic.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stdin --&amp;gt; Parser --&amp;gt; Visualizer --&amp;gt; Renderer --&amp;gt; ffmpeg --&amp;gt; .mp4
           |            |              |
           |            |              +-- PNG frames in temp dir
           |            +-- Trait: bars/line/scatter/gauge/heatmap
           +-- Regex, CSV, JSON, key=value, raw numbers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Parser&lt;/strong&gt; reads stdin line by line and extracts numeric values. It auto-detects format — raw numbers, CSV, JSON, key=value pairs — or you can specify a regex with &lt;code&gt;--pattern&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Visualizer&lt;/strong&gt; maintains state and renders each frame showing all data seen so far. This creates the "buildup" animation effect.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Renderer&lt;/strong&gt; generates PNG frames in a temp directory, then shells out to ffmpeg to encode them as MP4.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No external font dependencies. Text is rendered using a built-in 5x7 bitmap font drawn as rectangles. vizpipe works on any system without font configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  5 Visualization Modes
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bars&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Animated bar chart, color-coded by magnitude&lt;/td&gt;
&lt;td&gt;Comparing values, rankings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;line&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Self-drawing line graph with fill&lt;/td&gt;
&lt;td&gt;Time series, trends&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;scatter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Points appear one by one on a 2D plane&lt;/td&gt;
&lt;td&gt;Distributions, correlations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gauge&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Circular speedometer&lt;/td&gt;
&lt;td&gt;Single-metric monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;heatmap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Color-coded 2D grid&lt;/td&gt;
&lt;td&gt;Frequency analysis, density&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  5 Color Schemes
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scheme&lt;/th&gt;
&lt;th&gt;Vibe&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;default&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Blue to red gradient&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;neon&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cyan/magenta/yellow on dark&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ocean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cool blues and teals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sunset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Warm oranges and purples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mono&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;White on black, clean&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;1 100 | vizpipe &lt;span class="nt"&gt;--mode&lt;/span&gt; bars &lt;span class="nt"&gt;--color-scheme&lt;/span&gt; neon &lt;span class="nt"&gt;--bg-color&lt;/span&gt; &lt;span class="s2"&gt;"#0a0a0a"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; neon.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Data Format Auto-Detection
&lt;/h2&gt;

&lt;p&gt;vizpipe doesn't care what your data looks like. It figures it out.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Detection&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Raw numbers&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;42&lt;/code&gt;, &lt;code&gt;3.14&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Space/comma separated&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10 20 30&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSV&lt;/td&gt;
&lt;td&gt;&lt;code&gt;name,42,high&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;--column N&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{"latency": 42}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatic (top-level numerics)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Key=value&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cpu=85% mem=72%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regex&lt;/td&gt;
&lt;td&gt;&lt;code&gt;time=42.3ms&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;--pattern&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;Data visualization shouldn't require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Opening a browser&lt;/li&gt;
&lt;li&gt;Writing JavaScript&lt;/li&gt;
&lt;li&gt;Setting up Grafana&lt;/li&gt;
&lt;li&gt;Creating an account on some SaaS&lt;/li&gt;
&lt;li&gt;Uploading data to a third party&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes you just want to &lt;strong&gt;look&lt;/strong&gt; at your data. Pipe in, get video out. That's it.&lt;/p&gt;

&lt;p&gt;The Unix philosophy says: do one thing well, accept stdin, produce output. vizpipe follows that philosophy — except the output is an MP4 instead of text.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;p&gt;Written in &lt;strong&gt;Rust&lt;/strong&gt; using the &lt;code&gt;image&lt;/code&gt; and &lt;code&gt;imageproc&lt;/code&gt; crates for frame rendering. Video encoding via &lt;code&gt;ffmpeg&lt;/code&gt;. 68 tests. Zero runtime dependencies beyond ffmpeg.&lt;/p&gt;

&lt;p&gt;Why Rust? Because when you're generating hundreds of PNG frames and encoding video, speed matters. vizpipe processes data and renders frames fast enough that the bottleneck is ffmpeg, not the renderer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install from source&lt;/span&gt;
git clone https://github.com/LakshmiSravyaVedantham/vizpipe.git
&lt;span class="nb"&gt;cd &lt;/span&gt;vizpipe
cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Requires: Rust 1.70+, ffmpeg&lt;/span&gt;

&lt;span class="c"&gt;# Your first visualization&lt;/span&gt;
&lt;span class="nb"&gt;seq &lt;/span&gt;1 50 | vizpipe &lt;span class="nt"&gt;--mode&lt;/span&gt; bars &lt;span class="nt"&gt;-o&lt;/span&gt; first.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Star it if this is useful: &lt;a href="https://github.com/LakshmiSravyaVedantham/vizpipe" rel="noopener noreferrer"&gt;github.com/LakshmiSravyaVedantham/vizpipe&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Every pipe deserves a picture.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>visualization</category>
      <category>opensource</category>
      <category>cli</category>
    </item>
    <item>
      <title>I Never Record Code Reviews Anymore — My Rust Tool Turns Any Git Diff Into a Video</title>
      <dc:creator>Lakshmi Sravya Vedantham</dc:creator>
      <pubDate>Mon, 16 Mar 2026 17:36:50 +0000</pubDate>
      <link>https://forem.com/lakshmisravyavedantham/i-never-record-code-reviews-anymore-my-rust-tool-turns-any-git-diff-into-a-video-2o37</link>
      <guid>https://forem.com/lakshmisravyavedantham/i-never-record-code-reviews-anymore-my-rust-tool-turns-any-git-diff-into-a-video-2o37</guid>
      <description>&lt;p&gt;Code reviews are the most text-heavy part of software development. Walls of green and red. Inline comments. "LGTM" after skimming 400 lines.&lt;/p&gt;

&lt;p&gt;What if you could &lt;em&gt;watch&lt;/em&gt; a code review instead of reading it?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem Nobody Talks About
&lt;/h2&gt;

&lt;p&gt;Async code reviews lose context. You're staring at a diff, jumping between files, trying to reconstruct the &lt;em&gt;story&lt;/em&gt; of the change. Why was this deleted? What does this new function connect to?&lt;/p&gt;

&lt;p&gt;Video walkthroughs solve this. Senior engineers record Loom videos walking through PRs all the time. But recording takes 10x longer than writing comments. You have to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open a screen recorder&lt;/li&gt;
&lt;li&gt;Navigate to each file&lt;/li&gt;
&lt;li&gt;Talk through every change&lt;/li&gt;
&lt;li&gt;Edit out the "uh"s and wrong tabs&lt;/li&gt;
&lt;li&gt;Upload and share&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nobody does this for every PR. So we're stuck with text diffs.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Command. Animated Walkthrough.
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;patchcast &lt;span class="nt"&gt;--diff&lt;/span&gt; HEAD~1 &lt;span class="nt"&gt;-o&lt;/span&gt; review.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. &lt;strong&gt;PR URL in, MP4 out.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/LakshmiSravyaVedantham/patchcast" rel="noopener noreferrer"&gt;patchcast&lt;/a&gt; reads any git diff — commit ranges, branch comparisons, &lt;code&gt;.diff&lt;/code&gt; files — and generates an animated code walkthrough video with real syntax highlighting, smooth transitions, and a professional dark-theme aesthetic.&lt;/p&gt;

&lt;p&gt;No recording. No narration. No editing. The diff &lt;em&gt;is&lt;/em&gt; the video.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Animation Works
&lt;/h2&gt;

&lt;p&gt;Each file in the diff becomes a scene. The animation follows a deliberate sequence designed for readability:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Title Card (1s)&lt;/strong&gt; — Filename, language, change stats (+N/-N). You immediately know what file you're looking at and how big the change is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Code Reveal&lt;/strong&gt; — Lines appear progressively with full syntax highlighting. Not a screenshot — real parsed syntax via &lt;a href="https://github.com/trishume/syntect" rel="noopener noreferrer"&gt;syntect&lt;/a&gt;, supporting 30+ languages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Deletion Highlight&lt;/strong&gt; — Removed lines pulse red and fade out. Your eye is drawn exactly where code was removed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Addition Highlight&lt;/strong&gt; — New lines slide in with a green highlight, then normalize. The visual weight tells you "this is what matters."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Pause (0.5s)&lt;/strong&gt; — Hold the final state so you can actually read it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Crossfade (0.5s)&lt;/strong&gt; — Smooth transition to the next file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Title Card → Code Reveal → Deletions (red) → Additions (green) → Pause → Crossfade → Next File
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result: a video that tells the &lt;em&gt;story&lt;/em&gt; of a change, file by file, in the order that makes sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Commands
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Review your last commit&lt;/span&gt;
patchcast &lt;span class="nt"&gt;--diff&lt;/span&gt; HEAD~1 &lt;span class="nt"&gt;-o&lt;/span&gt; review.mp4

&lt;span class="c"&gt;# Compare branches (perfect for PR walkthroughs)&lt;/span&gt;
patchcast &lt;span class="nt"&gt;--diff&lt;/span&gt; main..feature-branch &lt;span class="nt"&gt;-o&lt;/span&gt; pr.mp4

&lt;span class="c"&gt;# Use a diff file with a custom theme&lt;/span&gt;
patchcast &lt;span class="nt"&gt;--file&lt;/span&gt; changes.diff &lt;span class="nt"&gt;--theme&lt;/span&gt; &lt;span class="s2"&gt;"Solarized (dark)"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; styled.mp4

&lt;span class="c"&gt;# Full customization&lt;/span&gt;
patchcast &lt;span class="nt"&gt;--diff&lt;/span&gt; HEAD~1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--theme&lt;/span&gt; &lt;span class="s2"&gt;"Solarized (dark)"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--font-size&lt;/span&gt; 18 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--fps&lt;/span&gt; 30 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--width&lt;/span&gt; 1920 &lt;span class="nt"&gt;--height&lt;/span&gt; 1080 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; review.mp4

&lt;span class="c"&gt;# Pipe from git&lt;/span&gt;
git diff main | patchcast &lt;span class="nt"&gt;--file&lt;/span&gt; /dev/stdin &lt;span class="nt"&gt;-o&lt;/span&gt; out.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where This Actually Gets Used
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Async code reviews&lt;/strong&gt; — Drop a video in the PR thread. Reviewers watch the change unfold instead of scrolling a diff. Context survives the async gap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Onboarding&lt;/strong&gt; — New engineer joins? Generate videos of the last 10 meaningful PRs. They watch the codebase evolve instead of reading stale wiki pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tech talks and demos&lt;/strong&gt; — Need to show a refactor in a presentation? One command, polished video. No screen recording, no "let me zoom in on this part."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt; — Embed walkthrough videos in architecture docs. Show &lt;em&gt;how&lt;/em&gt; the system changed, not just what it looks like now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Blog posts&lt;/strong&gt; — Writing about a technique? Generate a video of the actual code change instead of pasting static snippets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Under the Hood
&lt;/h2&gt;

&lt;p&gt;patchcast is written in Rust. The pipeline is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diff input → parse → syntax highlight → scene generation → frame rendering → ffmpeg → MP4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;diff_parser.rs&lt;/strong&gt; — Parses unified diff format into structured hunks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;highlighter.rs&lt;/strong&gt; — syntect-based syntax highlighting for 30+ languages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;scene.rs&lt;/strong&gt; — Converts parsed diffs into animation scenes with timing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;animation.rs&lt;/strong&gt; — Easing functions, interpolation, timing curves&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;renderer.rs&lt;/strong&gt; — Renders frames using the &lt;code&gt;image&lt;/code&gt; crate, pipes to ffmpeg&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;style.rs&lt;/strong&gt; — Dark theme (Catppuccin Mocha inspired), color constants&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The syntax highlighting is real — not regex-based approximation. syntect uses the same &lt;code&gt;.sublime-syntax&lt;/code&gt; definitions that power Sublime Text and bat. Rust, Python, JavaScript, TypeScript, Go, Java, C++, Ruby, Swift, and 20+ more languages are highlighted correctly out of the box.&lt;/p&gt;

&lt;p&gt;59 tests cover the full pipeline from diff parsing to frame generation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Rust?
&lt;/h2&gt;

&lt;p&gt;Frame rendering is CPU-intensive. Each frame is a pixel buffer that needs text layout, color blending, and composition. Rust makes this fast without a garbage collector pause mid-render. A typical 5-file diff renders in seconds.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;image&lt;/code&gt; crate handles pixel-level rendering. &lt;code&gt;git2&lt;/code&gt; (libgit2 bindings) reads the repository directly — no shelling out to &lt;code&gt;git&lt;/code&gt;. &lt;code&gt;syntect&lt;/code&gt; provides the highlighting. &lt;code&gt;ffmpeg&lt;/code&gt; handles the final encoding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/LakshmiSravyaVedantham/patchcast
&lt;span class="nb"&gt;cd &lt;/span&gt;patchcast
cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Prerequisites: Rust 1.70+, ffmpeg&lt;/span&gt;
&lt;span class="c"&gt;# macOS: brew install ffmpeg&lt;/span&gt;
&lt;span class="c"&gt;# Ubuntu: apt install ffmpeg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then point it at any repo:&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;your-project
patchcast &lt;span class="nt"&gt;--diff&lt;/span&gt; HEAD~1 &lt;span class="nt"&gt;-o&lt;/span&gt; walkthrough.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Star the repo if this is useful: &lt;a href="https://github.com/LakshmiSravyaVedantham/patchcast" rel="noopener noreferrer"&gt;github.com/LakshmiSravyaVedantham/patchcast&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Code reviews shouldn't require a recording studio. They should require one command.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>git</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I Built an AI Video Director That Turns Lessons Into Animated Videos</title>
      <dc:creator>Lakshmi Sravya Vedantham</dc:creator>
      <pubDate>Sun, 15 Mar 2026 20:58:11 +0000</pubDate>
      <link>https://forem.com/lakshmisravyavedantham/i-built-an-ai-video-director-that-turns-lessons-into-animated-videos-26o4</link>
      <guid>https://forem.com/lakshmisravyavedantham/i-built-an-ai-video-director-that-turns-lessons-into-animated-videos-26o4</guid>
      <description>&lt;p&gt;I run a kids' educational YouTube channel. Every video needs animations, voiceover, music, and careful editing — which means expensive software and hours of work per upload. Most teachers and content creators I know have the same problem: great lesson ideas, no way to turn them into videos.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;CutTo&lt;/strong&gt; to fix this. You describe a lesson in a conversation — "explain how volcanoes erupt for 8-year-olds" — and CutTo writes the script, generates animated visuals, adds voiceover with lipsync, and delivers a finished MP4 you can upload directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Talk to the director&lt;/strong&gt; — CutTo's AI has a creative director persona. It reacts to your ideas with enthusiasm: &lt;em&gt;"I'm seeing this as a cinematic journey into the earth — layers peeling away, magma rising..."&lt;/em&gt; It shapes your rough idea into a visual plan.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;See preview images inline&lt;/strong&gt; — As you plan, Gemini generates preview images directly in the conversation using interleaved text + image output. You see what the AI is thinking before committing to anything.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Edit the scene plan&lt;/strong&gt; — An interactive editor lets you modify narration, reorder scenes, change speakers, and ask the AI for revisions in natural language: "make the eruption more dramatic."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Watch it generate&lt;/strong&gt; — Real-time progress tracking shows each scene being animated in parallel. If a scene fails, the pipeline gracefully continues with the rest.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Download your video&lt;/strong&gt; — Multi-character voices, lipsync on close-ups, mood-matched background music. Ready to upload.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;CutTo supports 6 video categories: animated stories, science explainers, documentaries, tutorials, marketing videos, and motivational pieces. The project has 119 automated tests covering the pipeline, services, agent, and API.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real use case: kids' education
&lt;/h2&gt;

&lt;p&gt;Here's why this matters to me personally. My YouTube channel targets kids ages 6-12. A typical video — "How does the heart pump blood?" — requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing a kid-friendly script&lt;/li&gt;
&lt;li&gt;Finding or creating animated visuals&lt;/li&gt;
&lt;li&gt;Recording voiceover (or hiring someone)&lt;/li&gt;
&lt;li&gt;Adding background music&lt;/li&gt;
&lt;li&gt;Editing everything together in Premiere/DaVinci&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's 4-8 hours per video minimum, or $200+ if I outsource it.&lt;/p&gt;

&lt;p&gt;With CutTo, I describe the lesson, review the scene plan, and click generate. The entire process takes one conversation. The AI handles the creative direction, visual generation, voice synthesis, and assembly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tech stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Conversation + Planning&lt;/td&gt;
&lt;td&gt;Gemini 2.5 Flash (interleaved text + image)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Video Generation&lt;/td&gt;
&lt;td&gt;Veo 3.0 (cinematic clips) with FLOW prompt decomposition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image Fallback&lt;/td&gt;
&lt;td&gt;Imagen 4.0 + Gemini native image&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Voice Synthesis&lt;/td&gt;
&lt;td&gt;Google Cloud TTS (Journey/Chirp3 HD) + edge-tts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lipsync&lt;/td&gt;
&lt;td&gt;Wav2Lip&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assembly&lt;/td&gt;
&lt;td&gt;FFmpeg (Ken Burns, concat, music mixing)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent Framework&lt;/td&gt;
&lt;td&gt;Google ADK (3 specialized agents)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Python 3.11, FastAPI, WebSocket&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;React 18, Vite 5, Web Speech API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Docker (multi-stage), Google Cloud Run&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User speaks lesson idea
    |
    v
Gemini generates scene plan with inline preview images
    |
    v
Interactive scene editor (edit, reorder, revise with AI)
    |
    v
FLOW Prompt Decomposition (subject/action/camera/lighting/palette/texture)
    |
    v
Pipeline: Veo 3.0 -&amp;gt; TTS -&amp;gt; FFmpeg crossfade -&amp;gt; Final MP4
(staggered parallel batches, circuit breaker on failures)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ADK multi-agent architecture uses three specialized agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Creative Director&lt;/strong&gt; — shapes the vision, asks clarifying questions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storyboard Artist&lt;/strong&gt; — generates structured scene plans with visual prompts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestrator&lt;/strong&gt; — routes between agents based on conversation state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each agent has its own tools and system instructions. The Creative Director has access to image generation for inline previews; the Storyboard Artist outputs structured JSON that feeds directly into the video pipeline.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Gemini's interleaved output is the killer feature for creative tools.&lt;/strong&gt; Showing preview images &lt;em&gt;during&lt;/em&gt; the conversation — not after — makes planning feel immediate. The user sees what the AI is imagining and can redirect before any expensive generation happens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual consistency requires engineering.&lt;/strong&gt; I use a "visual style anchor" — a detailed description of art style, color palette, and character appearances — prepended to every scene's visual prompt. Combined with Veo's seed parameter (all scenes share a seed derived from video_id), characters and style stay consistent across scenes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audio-video sync is harder than it looks.&lt;/strong&gt; I implemented two modes: audio-driven (default — preserves natural voice speed, video adjusts) and video-driven (audio speeds up or pads to match video length). Getting FFmpeg's atempo chaining right for ratios &amp;gt; 2x was the trickiest bug in the project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The persona makes the product.&lt;/strong&gt; A generic "video generator" feels like a tool. A creative director with opinions and enthusiasm feels like a collaborator. The difference is entirely in the system prompt and conversation design.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/LakshmiSravyaVedantham/cutto.git
&lt;span class="nb"&gt;cd &lt;/span&gt;cutto
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; backend/requirements.txt
&lt;span class="nb"&gt;cd &lt;/span&gt;frontend &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; frontend/dist static
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"GOOGLE_API_KEY=your-key"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .env
uvicorn backend.main:app &lt;span class="nt"&gt;--reload&lt;/span&gt; &lt;span class="nt"&gt;--port&lt;/span&gt; 8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;a href="http://localhost:8000" rel="noopener noreferrer"&gt;http://localhost:8000&lt;/a&gt;, click a quick-start template like "How the heart pumps blood", and watch the AI direct your video.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://github.com/LakshmiSravyaVedantham/cutto" rel="noopener noreferrer"&gt;GitHub Repo&lt;/a&gt; | MIT License&lt;/p&gt;

&lt;p&gt;&lt;a href="https://studio.youtube.com/video/LnSa3-o4twA/edit" rel="noopener noreferrer"&gt;Youtube demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built for the Google Gemini Live Agent Challenge (Creative Storyteller category). Every existing tool makes you the editor. CutTo makes you the director.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>opensource</category>
      <category>geminiliveagentchallenge</category>
    </item>
    <item>
      <title>I Built a Breach Monitoring System That Runs in Your Terminal</title>
      <dc:creator>Lakshmi Sravya Vedantham</dc:creator>
      <pubDate>Thu, 12 Mar 2026 19:29:09 +0000</pubDate>
      <link>https://forem.com/lakshmisravyavedantham/i-built-a-breach-monitoring-system-that-runs-in-your-terminal-4l8i</link>
      <guid>https://forem.com/lakshmisravyavedantham/i-built-a-breach-monitoring-system-that-runs-in-your-terminal-4l8i</guid>
      <description>&lt;p&gt;I Built a Breach Monitoring System That Runs in Your Terminal&lt;/p&gt;

&lt;p&gt;Most people check if they've been breached once, maybe twice. Then they forget about it. Meanwhile, new breaches happen every week.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;leakwatch&lt;/strong&gt; — a personal breach monitoring system that watches your accounts continuously and only alerts you when something new happens.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;leakwatch

&lt;span class="c"&gt;# Add accounts to your watchlist&lt;/span&gt;
leakwatch watch personal@gmail.com
leakwatch watch work@company.com
leakwatch watch your_username

&lt;span class="c"&gt;# Scan for new breaches&lt;/span&gt;
leakwatch scan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key word is &lt;strong&gt;new&lt;/strong&gt;. leakwatch remembers what it has already told you about. It only alerts on breaches it has not seen before.&lt;/p&gt;

&lt;h2&gt;
  
  
  The dashboard
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;leakwatch dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shows your watchlist, new alerts with severity scores (1-10), pending actions, and overall stats. Everything in a clean terminal UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it is different from Have I Been Pwned
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;HIBP&lt;/th&gt;
&lt;th&gt;leakwatch&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Check email&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check username&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remember previous results&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Only show NEW breaches&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generate action plan&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Track your progress&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Severity scoring&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (1-10)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works offline&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Action tracking
&lt;/h2&gt;

&lt;p&gt;Every breach generates prioritized actions. CRITICAL for password leaks, HIGH for PII exposure, MEDIUM for email-only leaks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;leakwatch actions
leakwatch &lt;span class="k"&gt;done &lt;/span&gt;3
leakwatch status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Password checker
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;leakwatch check-password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uses k-anonymity. Only 5 characters of the hash leave your machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Everything stays local
&lt;/h2&gt;

&lt;p&gt;Built-in database of 30+ major breaches. Optional HIBP API key for real-time data. SQLite for all tracking. No cloud, no accounts, no telemetry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;leakwatch
leakwatch watch your-email@gmail.com
leakwatch scan
leakwatch dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub: &lt;a href="https://github.com/LakshmiSravyaVedantham/leakwatch" rel="noopener noreferrer"&gt;github.com/LakshmiSravyaVedantham/leakwatch&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This completes my privacy tools trilogy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/LakshmiSravyaVedantham/trackmap" rel="noopener noreferrer"&gt;trackmap&lt;/a&gt;&lt;/strong&gt; — map which companies track your browsing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/LakshmiSravyaVedantham/phantom" rel="noopener noreferrer"&gt;phantom&lt;/a&gt;&lt;/strong&gt; — find ghost accounts on breached services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/LakshmiSravyaVedantham/leakwatch" rel="noopener noreferrer"&gt;leakwatch&lt;/a&gt;&lt;/strong&gt; — monitor your accounts for new breaches&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All open source. All fully local. All pip-installable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Want all three in a single binary?
&lt;/h2&gt;

&lt;p&gt;I rewrote trackmap + phantom + leakwatch as one Rust binary: &lt;strong&gt;&lt;a href="https://github.com/LakshmiSravyaVedantham/privacykit" rel="noopener noreferrer"&gt;privacykit&lt;/a&gt;&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;cargo &lt;span class="nb"&gt;install &lt;/span&gt;privacykit
privacykit track scan &lt;span class="nt"&gt;--chrome&lt;/span&gt;
privacykit phantom scan you@gmail.com
privacykit leak scan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero Python. Zero dependencies. One binary.&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>security</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>You Have Accounts on 34 Services You Forgot About. 8 Were Breached.</title>
      <dc:creator>Lakshmi Sravya Vedantham</dc:creator>
      <pubDate>Thu, 12 Mar 2026 19:28:13 +0000</pubDate>
      <link>https://forem.com/lakshmisravyavedantham/you-have-accounts-on-34-services-you-forgot-about-8-were-breached-1751</link>
      <guid>https://forem.com/lakshmisravyavedantham/you-have-accounts-on-34-services-you-forgot-about-8-were-breached-1751</guid>
      <description>&lt;p&gt;Remember that Canva account from 2019? The MySpace one from way back? That random forum you signed up for once?&lt;/p&gt;

&lt;p&gt;Those accounts are still out there. And many of them have been breached — passwords leaked, email addresses sold, personal data floating around dark web dumps.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;phantom&lt;/strong&gt; to find them.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;phantom-accounts
phantom scan you@gmail.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;╭──────── GHOST ACCOUNT REPORT ────────╮
╰──────────────────────────────────────╯

  ⚠ you@gmail.com  12 breaches

    █ Adobe          2013-10-04  adobe.com
      Exposed: Passwords, Email addresses, Password hints

    █ Yahoo          2013-08-01  yahoo.com
      Exposed: Email addresses, Names, Passwords, Phone numbers

    █ LinkedIn       2021-06-22  linkedin.com
      Exposed: Email addresses, Names, Phone numbers

╭─ SUMMARY ────────────────────────────╮
│  Ghost accounts found: 12 services   │
│  Password leaks: 5                   │
│  Run phantom actions to fix them.    │
╰──────────────────────────────────────╯
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  It doesn't just find breaches — it tells you what to DO
&lt;/h2&gt;

&lt;p&gt;That's the key difference. Plenty of tools tell you "you were breached." phantom generates a &lt;strong&gt;prioritized action plan&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;phantom actions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csvs"&gt;&lt;code&gt;  &lt;span class="k"&gt;ID&lt;/span&gt;  &lt;span class="k"&gt;Priority&lt;/span&gt;    &lt;span class="k"&gt;Service&lt;/span&gt;     &lt;span class="k"&gt;Action&lt;/span&gt;
  &lt;span class="mf"&gt;1&lt;/span&gt;   &lt;span class="k"&gt;CRITICAL&lt;/span&gt;    &lt;span class="k"&gt;Adobe&lt;/span&gt;       &lt;span class="k"&gt;Change&lt;/span&gt; &lt;span class="k"&gt;password&lt;/span&gt;
  &lt;span class="mf"&gt;2&lt;/span&gt;   &lt;span class="k"&gt;CRITICAL&lt;/span&gt;    &lt;span class="k"&gt;Yahoo&lt;/span&gt;       &lt;span class="k"&gt;Change&lt;/span&gt; &lt;span class="k"&gt;password&lt;/span&gt;
  &lt;span class="mf"&gt;3&lt;/span&gt;   &lt;span class="k"&gt;HIGH&lt;/span&gt;        &lt;span class="k"&gt;Adobe&lt;/span&gt;       &lt;span class="k"&gt;Enable&lt;/span&gt; &lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="k"&gt;FA&lt;/span&gt;
  &lt;span class="mf"&gt;4&lt;/span&gt;   &lt;span class="k"&gt;HIGH&lt;/span&gt;        &lt;span class="k"&gt;LinkedIn&lt;/span&gt;    &lt;span class="k"&gt;Enable&lt;/span&gt; &lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="k"&gt;FA&lt;/span&gt;
  &lt;span class="mf"&gt;5&lt;/span&gt;   &lt;span class="k"&gt;HIGH&lt;/span&gt;        &lt;span class="k"&gt;Marriott&lt;/span&gt;    &lt;span class="k"&gt;Review&lt;/span&gt; &lt;span class="k"&gt;account&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;PII&lt;/span&gt; &lt;span class="k"&gt;exposed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you track your progress:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;phantom &lt;span class="k"&gt;done &lt;/span&gt;1    &lt;span class="c"&gt;# mark as completed&lt;/span&gt;
phantom skip 5    &lt;span class="c"&gt;# skip if not applicable&lt;/span&gt;
phantom status    &lt;span class="c"&gt;# see overall progress&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Password checker
&lt;/h2&gt;

&lt;p&gt;Check if a password has been seen in any data breach — using k-anonymity so your actual password never leaves your machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;phantom check-password
Enter password to check: &lt;span class="k"&gt;****&lt;/span&gt;
⚠ Password p4&lt;span class="k"&gt;******&lt;/span&gt; has been seen 847 &lt;span class="nb"&gt;times &lt;/span&gt;&lt;span class="k"&gt;in &lt;/span&gt;data breaches.
Change this password immediately.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Built-in database of 20+ major breaches covering 3 billion+ accounts&lt;/li&gt;
&lt;li&gt;Optional HIBP API integration for real-time results&lt;/li&gt;
&lt;li&gt;Actions auto-generated based on what was exposed (passwords = CRITICAL, PII = HIGH)&lt;/li&gt;
&lt;li&gt;Local SQLite database tracks your response progress&lt;/li&gt;
&lt;li&gt;Everything runs on your machine&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;phantom-accounts
phantom scan your-email@gmail.com
phantom actions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub: &lt;a href="https://github.com/LakshmiSravyaVedantham/phantom" rel="noopener noreferrer"&gt;github.com/LakshmiSravyaVedantham/phantom&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Part of my privacy tools suite. Also check out &lt;a href="https://github.com/LakshmiSravyaVedantham/trackmap" rel="noopener noreferrer"&gt;trackmap&lt;/a&gt; (map your tracking network) and &lt;a href="https://github.com/LakshmiSravyaVedantham/leakwatch" rel="noopener noreferrer"&gt;leakwatch&lt;/a&gt; (continuous breach monitoring).&lt;/p&gt;




&lt;h2&gt;
  
  
  Want all three in a single binary?
&lt;/h2&gt;

&lt;p&gt;I rewrote trackmap + phantom + leakwatch as one Rust binary: &lt;strong&gt;&lt;a href="https://github.com/LakshmiSravyaVedantham/privacykit" rel="noopener noreferrer"&gt;privacykit&lt;/a&gt;&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;cargo &lt;span class="nb"&gt;install &lt;/span&gt;privacykit
privacykit track scan &lt;span class="nt"&gt;--chrome&lt;/span&gt;
privacykit phantom scan you@gmail.com
privacykit leak scan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero Python. Zero dependencies. One binary.&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>security</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Google Can See 78% of Your Browsing History — I Built a Tool to Prove It</title>
      <dc:creator>Lakshmi Sravya Vedantham</dc:creator>
      <pubDate>Thu, 12 Mar 2026 19:28:10 +0000</pubDate>
      <link>https://forem.com/lakshmisravyavedantham/google-can-see-78-of-your-browsing-history-i-built-a-tool-to-prove-it-3mmn</link>
      <guid>https://forem.com/lakshmisravyavedantham/google-can-see-78-of-your-browsing-history-i-built-a-tool-to-prove-it-3mmn</guid>
      <description>&lt;p&gt;Every website you visit is quietly loading invisible scripts from tracking companies. Ad networks, analytics platforms, fingerprinting services — they're all there, stitching together a profile of you across every site you touch.&lt;/p&gt;

&lt;p&gt;I wanted to know exactly who's watching. So I built &lt;strong&gt;trackmap&lt;/strong&gt;.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;trackmap
trackmap scan &lt;span class="nt"&gt;--chrome&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;trackmap reads your browser history (Chrome, Firefox, or Safari), fetches each site, extracts every third-party script, pixel, and iframe, and maps out which companies are tracking you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TRACKING NETWORK REPORT
━━━━━━━━━━━━━━━━━━━━━━
Sites scanned:    87
Trackers found:   23 companies across 312 connections

TOP TRACKERS BY REACH
  Google                    ██████████████████░░  78.2% of your browsing
  Meta                      █████████░░░░░░░░░░░  41.3%
  Amazon                    ██████░░░░░░░░░░░░░░  29.1%
  Oracle                    ████░░░░░░░░░░░░░░░░  18.4%
  Criteo                    ███░░░░░░░░░░░░░░░░░  14.9%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Import&lt;/strong&gt; your browser history from Chrome/Firefox/Safari&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scan&lt;/strong&gt; the top 100 most-visited sites (async, fast)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extract&lt;/strong&gt; every third-party domain from scripts, iframes, pixels, inline URLs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Match&lt;/strong&gt; against a built-in database of 163 tracker domains from 72 companies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Report&lt;/strong&gt; with bar charts, categories, and a privacy risk score&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Five categories: Advertising, Analytics, Social, Fingerprinting, and Content delivery.&lt;/p&gt;

&lt;h2&gt;
  
  
  The scariest part
&lt;/h2&gt;

&lt;p&gt;It's not just that Google tracks you. It's that companies you've &lt;strong&gt;never heard of&lt;/strong&gt; — Criteo, BlueKai, LiveRamp — are embedded across dozens of your most-visited sites, building a shadow profile of your interests, habits, and behavior.&lt;/p&gt;

&lt;p&gt;trackmap also shows &lt;strong&gt;unknown third-party domains&lt;/strong&gt; that aren't in any tracker database. These are potential new trackers that haven't been catalogued yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Privacy
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Your history never leaves your machine&lt;/li&gt;
&lt;li&gt;All scanning happens locally&lt;/li&gt;
&lt;li&gt;No API keys needed&lt;/li&gt;
&lt;li&gt;Works on a copy of your browser DB (doesn't touch the original)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;trackmap
trackmap scan &lt;span class="nt"&gt;--chrome&lt;/span&gt; &lt;span class="nt"&gt;--top&lt;/span&gt; 50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or check if a specific domain is a known tracker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;trackmap check doubleclick.net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub: &lt;a href="https://github.com/LakshmiSravyaVedantham/trackmap" rel="noopener noreferrer"&gt;github.com/LakshmiSravyaVedantham/trackmap&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This is part of a privacy tools suite I'm building. Also check out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/LakshmiSravyaVedantham/shadowscan" rel="noopener noreferrer"&gt;shadowscan&lt;/a&gt; — what AI can see about you locally&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/LakshmiSravyaVedantham/datawipe" rel="noopener noreferrer"&gt;datawipe&lt;/a&gt; — automate GDPR/CCPA data deletion requests&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/LakshmiSravyaVedantham/consentmap" rel="noopener noreferrer"&gt;consentmap&lt;/a&gt; — privacy policy scanner&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/LakshmiSravyaVedantham/phantom" rel="noopener noreferrer"&gt;phantom&lt;/a&gt; — find your ghost accounts on breached services&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Want all three in a single binary?
&lt;/h2&gt;

&lt;p&gt;I rewrote trackmap + phantom + leakwatch as one Rust binary: &lt;strong&gt;&lt;a href="https://github.com/LakshmiSravyaVedantham/privacykit" rel="noopener noreferrer"&gt;privacykit&lt;/a&gt;&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;cargo &lt;span class="nb"&gt;install &lt;/span&gt;privacykit
privacykit track scan &lt;span class="nt"&gt;--chrome&lt;/span&gt;
privacykit phantom scan you@gmail.com
privacykit leak scan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero Python. Zero dependencies. One binary.&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>security</category>
      <category>python</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
