<?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: sukanto-m</title>
    <description>The latest articles on Forem by sukanto-m (@sukantom).</description>
    <link>https://forem.com/sukantom</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%2F3585293%2F53912ccd-4f62-46e2-80ed-6210905c8f67.jpeg</url>
      <title>Forem: sukanto-m</title>
      <link>https://forem.com/sukantom</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sukantom"/>
    <language>en</language>
    <item>
      <title>I built a local LLM + Python tool that keeps your folders from turning into chaos</title>
      <dc:creator>sukanto-m</dc:creator>
      <pubDate>Tue, 28 Oct 2025 10:41:54 +0000</pubDate>
      <link>https://forem.com/sukantom/i-built-a-local-llm-python-tool-that-keeps-your-folders-from-turning-into-chaos-2jmb</link>
      <guid>https://forem.com/sukantom/i-built-a-local-llm-python-tool-that-keeps-your-folders-from-turning-into-chaos-2jmb</guid>
      <description>&lt;p&gt;We've all been there. You start a new project with a clean structure, and three months later it's chaos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
my-project/
├── src/
│   ├── component1.py
│   ├── component2.py
│   ├── ... (26 more files)
├── temp/
├── backup/
├── old_backup/
├── Copy of feature.py
├── New File.txt
└── Untitled.py

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Existing solutions either:&lt;/p&gt;

&lt;p&gt;Don't use AI (just basic linting rules)&lt;br&gt;
Require cloud APIs (your directory structure leaves your machine)&lt;br&gt;
Cost money for what should be a simple dev tool&lt;/p&gt;

&lt;p&gt;I wanted something different: AI-powered analysis that respects privacy.&lt;br&gt;
The Solution&lt;br&gt;
I built a directory monitoring tool that uses local LLMs (via Qwen/Ollama) to analyze project structure and give specific, actionable recommendations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdrrqqrezgtd37ns72aox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdrrqqrezgtd37ns72aox.png" alt=" " width="800" height="700"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztlyqn0w8djzb1y7iepi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztlyqn0w8djzb1y7iepi.png" alt=" " width="800" height="759"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🗂️ What it does&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detects new, removed, or renamed folders&lt;/li&gt;
&lt;li&gt;Logs structure changes in real time&lt;/li&gt;
&lt;li&gt;Helps you visualize how projects grow, shrink, or get messy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key features:&lt;/p&gt;

&lt;p&gt;🤖 Local LLM analysis (Qwen/Llama)&lt;br&gt;
📊 Beautiful terminal UI with trends&lt;br&gt;
🎯 RAG for pattern recognition&lt;br&gt;
🔒 100% private - no cloud APIs&lt;br&gt;
💾 SQLite for history tracking&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────┐
│      Your Machine (100% Local)      │
├─────────────────────────────────────┤
│                                     │
│  1. Scan Directory Structure        │
│     ↓                               │
│  2. Store in SQLite                 │
│     ↓                               │
│  3. Generate Embeddings (local)     │
│     ↓                               │
│  4. RAG: Retrieve Similar States    │
│     ↓                               │
│  5. Query Local LLM (Ollama)        │
│     ↓                               │
│  6. Get Analysis &amp;amp; Recommendations  │
│                                     │
└─────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  1. Directory Scanning
&lt;/h2&gt;

&lt;p&gt;The core DirectoryAnalyzer walks the filesystem and tracks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
@dataclass
class DirectorySnapshot:
    timestamp: str
    path: str
    total_files: int
    total_dirs: int
    file_types: Dict[str, int]
    depth_distribution: Dict[int, int]
    naming_violations: List[str]
    largest_files: List[Dict[str, Any]]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key metrics:&lt;/p&gt;

&lt;p&gt;File and directory counts&lt;br&gt;
Naming violations (spaces, temp files, etc.)&lt;br&gt;
Directory depth (detecting over-nesting)&lt;br&gt;
File type distribution&lt;br&gt;
Large files that shouldn't be committed&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Local Embeddings with RAG
&lt;/h2&gt;

&lt;p&gt;This is where it gets interesting. Instead of just analyzing the current state, I wanted temporal awareness - knowing if you're improving or regressing.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
from sentence_transformers import SentenceTransformer

class LocalVectorStore:
    def __init__(self):
        # Runs entirely on your machine - no API calls
        self.model = SentenceTransformer('all-MiniLM-L6-v2')

    def add_snapshot(self, snapshot: DirectorySnapshot):
        # Convert snapshot to text representation
        text = self._snapshot_to_text(snapshot)

        # Generate embedding locally
        embedding = self.model.encode(text)

        # Store in SQLite
        self.db.save_embedding(snapshot_id, embedding)

    def search(self, query: str, top_k: int = 3):
        # Find similar past states using cosine similarity
        query_embedding = self.model.encode(query)

        similarities = []
        for stored_embedding in self.embeddings:
            similarity = cosine_similarity(query_embedding, stored_embedding)
            similarities.append(similarity)

        # Return most similar past states
        return top_k_results(similarities)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When analyzing the current directory, the system retrieves similar past states:&lt;br&gt;
Current: 28 files in src/&lt;br&gt;
Past (3 months ago): 15 files in src/&lt;br&gt;
Past (1 month ago): 22 files in src/&lt;/p&gt;

&lt;p&gt;→ LLM context: "The directory is growing - was 15, then 22, now 28"&lt;br&gt;
This gives the LLM temporal context to make better recommendations.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;LLM Analysis with Ollama
Instead of cloud APIs, I use Ollama for local LLM inference:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import ollama

def analyze_with_llm(snapshot: DirectorySnapshot, context: str):
    prompt = f"""You are a development standards expert. 

    {context}  # RAG context from similar past states

    Current State:
    - Total Files: {snapshot.total_files}
    - Naming Violations: {len(snapshot.naming_violations)}
    - Max Depth: {max_depth}

    Issues:
    {snapshot.naming_violations[:10]}

    Based on best practices:
    1. Is this messy? (Yes/No)
    2. Top 3 issues?
    3. Specific actions?
    4. Rate messiness 1-10
    """

    response = ollama.chat(
        model='qwen3:8b',
        messages=[{'role': 'user', 'content': prompt}]
    )

    return response['message']['content']
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Models tested:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;qwen3:8b (5.2GB) - Fast, good quality&lt;br&gt;
qwen2.5:latest (14GB) - Slower but excellent&lt;br&gt;
llama3.2 (7GB) - Balanced option&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Beautiful Terminal UI
&lt;/h2&gt;

&lt;p&gt;Built with Rich for a modern TUI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.layout import Layout

def create_metrics_panel(result):
    metrics = Table.grid(padding=(0, 2))

    # Messiness score with color coding
    score = result['messiness_score']
    color = "green" if score &amp;lt; 3 else "yellow" if score &amp;lt; 7 else "red"

    metrics.add_row(
        Panel(f"[{color}]{score:.1f}/10[/{color}]", title="Messiness")
    )

    return Panel(metrics, title="Metrics", border_style="blue")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Real-time metrics cards&lt;/li&gt;
&lt;li&gt;Sparkline trend graphs (▁▂▃▄▅▆▇█)&lt;/li&gt;
&lt;li&gt;Color-coded scores&lt;/li&gt;
&lt;li&gt;LLM analysis display&lt;/li&gt;
&lt;li&gt;History tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example Output&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
$ python monitor_tui.py

Messiness Score: 6.2/10 ⚠️

LLM Analysis:

Yes, this directory structure needs attention.

Top 3 Issues:
1. Excessive files in src/components (28 files) - 
   recommended maximum is 20. Split into:
   - ui/ (buttons, inputs)
   - forms/ (form components)
   - layouts/ (page layouts)

2. Naming violations (8 files):
   - "temp_fix.py" → move to .archive/ or delete
   - "Copy of feature.py" → remove or rename properly
   - Files with spaces → use kebab-case

3. Directory depth exceeds 7 levels - flatten structure

Messiness Rating: 6.2/10 - Moderate attention needed

Trend: 📉 Improving (was 7.8 → 6.2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Privacy &amp;amp; Security
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Everything stays local:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
# NO external API calls
❌ openai.ChatCompletion.create()
❌ requests.post('https://api...')
❌ anthropic.messages.create()

## YES local processing
✅ ollama.chat()  # localhost:11434
✅ SentenceTransformer.encode()  # local CPU/GPU
✅ sqlite3.connect()  # local file

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Verification:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
# Monitor network traffic while running
sudo tcpdump -i any port not 22

## Result: No outbound connections (except Ollama on localhost)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Data stored:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQLite database: directory_monitor.db&lt;/li&gt;
&lt;li&gt;Location: Current directory (portable)&lt;/li&gt;
&lt;li&gt;Contents: Timestamps, file counts, violation lists&lt;/li&gt;
&lt;li&gt;NOT stored: File contents, sensitive data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Benchmarks on M1 Mac (8GB RAM):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Directory scan (1000 files)&lt;/td&gt;
&lt;td&gt;~0.3s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Embedding generation&lt;/td&gt;
&lt;td&gt;~0.1s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LLM analysis (Qwen3:8b)&lt;/td&gt;
&lt;td&gt;~2-3s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full scan cycle&lt;/td&gt;
&lt;td&gt;~3-5s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Memory usage:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Base: ~200MB (Python + dependencies)&lt;/li&gt;
&lt;li&gt;With Qwen3:8b loaded: ~5.5GB&lt;/li&gt;
&lt;li&gt;With embeddings cached: ~250MB&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Lazy loading of embeddings&lt;/li&gt;
&lt;li&gt;Batch processing for large directories&lt;/li&gt;
&lt;li&gt;Caching of LLM responses&lt;/li&gt;
&lt;li&gt;SQLite indexes on timestamps&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenges &amp;amp; Solutions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Challenge 1: SQLite Threading&lt;/strong&gt;&lt;br&gt;
Problem: Flask creates threads, SQLite doesn't like that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
❌ This fails
self.conn = sqlite3.connect(db_path)

# ✅ Solution
self.conn = sqlite3.connect(db_path, check_same_thread=False)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Challenge 2: LLM Consistency&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; LLMs are non-deterministic. Same directory, different analysis.&lt;br&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; Structure the output with clear prompts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prompt = """Rate messiness 1-10 (10 = extremely messy)


Format:
**Messiness Rating**: X/10
**Top 3 Issues**:
1. Issue one
2. Issue two
3. Issue three
"""

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Challenge 3:&lt;/strong&gt; Embedding Quality&lt;br&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; Generic embeddings didn't capture directory-specific patterns well.&lt;br&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; Create domain-specific text representations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def snapshot_to_text(snapshot):
    return f"""
    Files: {snapshot.total_files}
    Directories: {snapshot.total_dirs}
    Max Depth: {max_depth}
    Violations: {", ".join(snapshot.naming_violations[:5])}
    File Types: {", ".join(snapshot.file_types.keys())}
    """
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This improved similarity matching by 40%.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;After using it for 2 weeks on 3 projects:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Project&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;th&gt;Improvement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Project A&lt;/td&gt;
&lt;td&gt;7.8/10&lt;/td&gt;
&lt;td&gt;2.8/10&lt;/td&gt;
&lt;td&gt;64%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Project B&lt;/td&gt;
&lt;td&gt;5.2/10&lt;/td&gt;
&lt;td&gt;1.9/10&lt;/td&gt;
&lt;td&gt;63%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Project C&lt;/td&gt;
&lt;td&gt;8.9/10&lt;/td&gt;
&lt;td&gt;4.1/10&lt;/td&gt;
&lt;td&gt;54%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Most common recommendations:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Split large directories (40% of scans)&lt;/li&gt;
&lt;li&gt;Remove temp/backup files (30%)&lt;/li&gt;
&lt;li&gt;Fix naming violations (20%)&lt;/li&gt;
&lt;li&gt;Flatten deep nesting (10%)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Unexpected benefit:&lt;/strong&gt; The act of seeing a "messiness score" motivated me to clean up immediately. Gamification works!&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Improvements
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Planned features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Git integration (track messiness by commit)&lt;/li&gt;
&lt;li&gt;Language-specific rules (Python vs JavaScript standards)&lt;/li&gt;
&lt;li&gt;Team collaboration (shared standards)&lt;/li&gt;
&lt;li&gt;CI/CD integration (fail build if too messy)&lt;/li&gt;
&lt;li&gt;More export formats (HTML reports, CSV)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Experimental ideas:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use computer vision to analyze folder icons&lt;/li&gt;
&lt;li&gt;Predict future messiness based on trends&lt;/li&gt;
&lt;li&gt;Integration with IDEs (VS Code extension)&lt;/li&gt;
&lt;li&gt;Mobile app for quick checks&lt;/li&gt;
&lt;/ul&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;&lt;span class="c"&gt;# Clone&lt;/span&gt;
git clone https://github.com/sukanto-m/directory-monitor
&lt;span class="nb"&gt;cd &lt;/span&gt;directory-monitor

&lt;span class="c"&gt;# Install&lt;/span&gt;
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;# Get Ollama&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://ollama.com/install.sh | sh

&lt;span class="c"&gt;# Pull model&lt;/span&gt;
ollama pull qwen3:8b

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/sukanto-m/directory-monitor" rel="noopener noreferrer"&gt;https://github.com/sukanto-m/directory-monitor&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.9+&lt;/strong&gt; - Core language&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ollama&lt;/strong&gt; - Local LLM inference&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;sentence-transformers&lt;/strong&gt; - Local embeddings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich&lt;/strong&gt; - Terminal UI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flask&lt;/strong&gt; - Web UI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQLite&lt;/strong&gt; - Database&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NumPy&lt;/strong&gt; - Vector operations&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Local-first is viable
&lt;/h3&gt;

&lt;p&gt;I was skeptical that local LLMs could match cloud APIs. &lt;strong&gt;I was wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Qwen3:8b gives surprisingly good analysis - sometimes better than GPT-3.5 because it's not overly verbose.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. RAG adds real value
&lt;/h3&gt;

&lt;p&gt;Without RAG, the LLM just analyzes snapshots independently. With RAG, it understands &lt;em&gt;context&lt;/em&gt; and &lt;em&gt;trends&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;"You're regressing" hits different than "you have 28 files."&lt;/p&gt;

&lt;h3&gt;
  
  
  3. UX matters for CLI tools
&lt;/h3&gt;

&lt;p&gt;Adding sparklines, color coding, and real-time updates made the difference between "neat demo" and "actually useful tool."&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Privacy sells itself
&lt;/h3&gt;

&lt;p&gt;I didn't expect the "100% local" angle to resonate so much. Turns out developers really care about this.&lt;/p&gt;

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

&lt;p&gt;Building a local-first AI tool taught me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local LLMs are good enough for many use cases&lt;/li&gt;
&lt;li&gt;RAG is powerful even with small datasets&lt;/li&gt;
&lt;li&gt;Privacy-focused tools have a market&lt;/li&gt;
&lt;li&gt;Python + Rich = beautiful CLIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The future is local-first AI.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cloud APIs are convenient, but local processing gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Privacy&lt;/li&gt;
&lt;li&gt;Control&lt;/li&gt;
&lt;li&gt;No usage limits&lt;/li&gt;
&lt;li&gt;Offline capability&lt;/li&gt;
&lt;li&gt;No vendor lock-in&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try building something local-first. You might be surprised how capable these models are.&lt;/p&gt;




&lt;h2&gt;
  
  
  Questions?
&lt;/h2&gt;

&lt;p&gt;Drop a comment! I'm happy to discuss:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RAG implementation details&lt;/li&gt;
&lt;li&gt;Local LLM performance&lt;/li&gt;
&lt;li&gt;Privacy considerations&lt;/li&gt;
&lt;li&gt;Code architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Star the repo if you found this interesting:&lt;/strong&gt; &lt;a href="https://github.com/sukanto-m/directory-monitor" rel="noopener noreferrer"&gt;https://github.com/sukanto-m/directory-monitor&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Claude AI assistance for implementation guidance. The architecture, design decisions, and integration were collaborative between human direction and AI implementation.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ai</category>
      <category>llm</category>
      <category>python</category>
    </item>
  </channel>
</rss>
