<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sam Hartley</title>
    <description>The latest articles on DEV Community by Sam Hartley (@samhartley_dev).</description>
    <link>https://dev.to/samhartley_dev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3811539%2Fdd554e30-699d-42a3-a82a-77673790a186.png</url>
      <title>DEV Community: Sam Hartley</title>
      <link>https://dev.to/samhartley_dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/samhartley_dev"/>
    <language>en</language>
    <item>
      <title>I Ditched ChatGPT for Local LLMs and Saved $2,000 in a Year — The Real Numbers</title>
      <dc:creator>Sam Hartley</dc:creator>
      <pubDate>Tue, 07 Jul 2026 08:02:10 +0000</pubDate>
      <link>https://dev.to/samhartley_dev/i-ditched-chatgpt-for-local-llms-and-saved-2000-in-a-year-the-real-numbers-2f8h</link>
      <guid>https://dev.to/samhartley_dev/i-ditched-chatgpt-for-local-llms-and-saved-2000-in-a-year-the-real-numbers-2f8h</guid>
      <description>&lt;p&gt;"Just use ChatGPT." — I heard this for months. And I did. Until I got the bill.&lt;/p&gt;

&lt;p&gt;$187 in one month. For a solo dev running side projects. That was my wake-up call.&lt;/p&gt;

&lt;p&gt;This is the story of how I went from cloud-only to a hybrid setup, what it actually cost, and where local models fall flat on their face.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup (July 2025)
&lt;/h2&gt;

&lt;p&gt;I was using three APIs daily:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI GPT-4o for code review and general questions&lt;/li&gt;
&lt;li&gt;Anthropic Claude Sonnet for writing and reasoning&lt;/li&gt;
&lt;li&gt;Google Gemini Pro for quick tasks and summaries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My workload wasn't enterprise-level. Maybe 300-500 queries per day across all projects — a mix of coding help, content drafting, data extraction, and random "what's the difference between these two Python libraries" questions.&lt;/p&gt;

&lt;p&gt;The bill for June 2025: &lt;strong&gt;$187.42&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For context, that's more than my internet bill, my streaming subscriptions, and my VPS combined.&lt;/p&gt;

&lt;h2&gt;
  
  
  Month 1: The Experiment
&lt;/h2&gt;

&lt;p&gt;I bought a used RTX 3060 12GB off eBay for $150. Added it to my existing PC (which already had a decent CPU). Installed Ollama. Pulled Qwen 2.5 7B.&lt;/p&gt;

&lt;p&gt;Took 20 minutes from "unboxing" to "first local query".&lt;/p&gt;

&lt;p&gt;The result? For simple questions — "explain this regex", "refactor this function", "summarize this text" — the 7B model was about 85% as good as GPT-4o. The answers were slightly less polished, sometimes missing nuance, but &lt;strong&gt;good enough&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The catch? Complex reasoning. I asked it to design a database schema for a multi-tenant app with row-level security. It gave me something that looked right but had a subtle flaw that would have caused data leaks in production.&lt;/p&gt;

&lt;p&gt;GPT-4o caught that flaw. The local model didn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson learned:&lt;/strong&gt; Local models are great for 80% of tasks. The other 20% still needs the big guns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Hybrid
&lt;/h2&gt;

&lt;p&gt;By month 3, I had a routing system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Query comes in
  → Is it simple? (explain, refactor, summarize)
    → Local model (free, ~2s)
  → Is it code review?
    → Local coder model (free, ~8s)
  → Is it complex reasoning or architecture?
    → Cloud API ($0.003-0.02 per query)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I didn't build anything fancy. Just a 30-line Python script that checks the query type and routes it. The "complexity check" is embarrassingly simple — if the query contains words like "architecture", "design", "security", "performance", or is longer than 500 characters, it goes to the cloud.&lt;/p&gt;

&lt;p&gt;Is it perfect? No. Does it catch edge cases? Sometimes. But it's &lt;strong&gt;good enough&lt;/strong&gt; and saved me a fortune.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers (12 Months)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cloud-Only Year (Hypothetical)
&lt;/h3&gt;

&lt;p&gt;If I kept my June 2025 pace: $187/month × 12 = &lt;strong&gt;$2,244/year&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Actual Hybrid Year
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Used RTX 3060 12GB&lt;/td&gt;
&lt;td&gt;$150 (one-time)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Electricity (GPU running 24/7)&lt;/td&gt;
&lt;td&gt;~$12/month = $144/year&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud API usage (reduced)&lt;/td&gt;
&lt;td&gt;~$25/month = $300/year&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total first year&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$594&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total subsequent years&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$444/year&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Savings: $2,244 - $594 = $1,650 in year one.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After the GPU is paid off, it's $444/year vs $2,244. The GPU pays for itself in under 4 months.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Surprised Me
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Latency is better locally.&lt;/strong&gt; Cloud APIs average 500-2000ms. My local setup answers in 200-800ms depending on model size. For iterative coding (write, test, ask, fix), that speed difference matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Privacy is underrated.&lt;/strong&gt; I started piping customer support tickets through the local model for sentiment analysis and categorization. With cloud APIs, I'd need a data processing agreement. With local? The data never leaves my machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rate limits don't exist locally.&lt;/strong&gt; Hit a deadline and need to process 1000 queries in an hour? Cloud APIs throttle you. Local hardware just gets warm.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model management is annoying.&lt;/strong&gt; Updates, storage (each model is 4-15GB), keeping track of which model does what — it's overhead. Not huge, but real.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Local Models Fail (Honestly)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Frontier reasoning.&lt;/strong&gt; I asked DeepSeek R1 70B (local, quantized) and Claude 3.5 Sonnet (cloud) to debug a race condition in my async Python code. Claude spotted it in 2 sentences. The local model gave me a 3-paragraph explanation that was technically correct but missed the actual bug.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creative writing.&lt;/strong&gt; GPT-4o writes prose that flows. Local models write prose that... exists. For marketing copy or user-facing content, I still use the cloud.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multimodal.&lt;/strong&gt; Local vision models exist but they're not great. If I need to analyze a screenshot or diagram, cloud wins hands down.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Actual Recommendation
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your Situation&lt;/th&gt;
&lt;th&gt;What to Do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Solo dev, side projects&lt;/td&gt;
&lt;td&gt;Local only. Start with Ollama + Qwen 2.5 7B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Small team, some budget&lt;/td&gt;
&lt;td&gt;Hybrid. Local for 80%, cloud for complex stuff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup with VC funding&lt;/td&gt;
&lt;td&gt;Hybrid. Local default, cloud for frontier tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enterprise with compliance needs&lt;/td&gt;
&lt;td&gt;Local + air-gapped. Cloud only for non-sensitive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"I just want it to work"&lt;/td&gt;
&lt;td&gt;Cloud. But you're paying for convenience&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Getting Started (10 Minutes)
&lt;/h2&gt;

&lt;p&gt;If you're curious, here's the fastest path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Install 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;# 2. Pull a model (7B fits in 8GB RAM)&lt;/span&gt;
ollama pull qwen2.5:7b

&lt;span class="c"&gt;# 3. Start chatting&lt;/span&gt;
ollama run qwen2.5:7b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Total time: 10 minutes. Total cost: $0.&lt;/p&gt;

&lt;p&gt;If you have an old gaming GPU lying around, you're golden. If not, CPU-only works for smaller models. It's slower but still usable for casual queries.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Honest Bottom Line
&lt;/h2&gt;

&lt;p&gt;Local LLMs aren't a magic bullet. They're a &lt;strong&gt;cost optimization&lt;/strong&gt; with trade-offs.&lt;/p&gt;

&lt;p&gt;You lose some quality on complex tasks. You gain speed, privacy, and massive cost savings. For me, routing 80% of queries locally dropped my AI bill from $187/month to $25/month.&lt;/p&gt;

&lt;p&gt;That's $1,650/year I can spend on... literally anything else.&lt;/p&gt;

&lt;p&gt;If you've tried local LLMs, what's your experience? Did the quality drop bother you, or was the cost saving worth it?&lt;/p&gt;

&lt;p&gt;Drop your setup in the comments — always curious how others are handling this.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Sam Hartley is a solo dev building tools on a Mac Mini + RTX 3060 home lab. Writes about the messy reality of shipping stuff with AI.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>selfhosted</category>
      <category>ollama</category>
    </item>
    <item>
      <title>I Built a Morning Briefing Bot in 50 Lines of Python — Here's Why I Check Telegram Before Email Now</title>
      <dc:creator>Sam Hartley</dc:creator>
      <pubDate>Wed, 01 Jul 2026 08:05:34 +0000</pubDate>
      <link>https://dev.to/samhartley_dev/i-built-a-morning-briefing-bot-in-50-lines-of-python-heres-why-i-check-telegram-before-email-now-3fhh</link>
      <guid>https://dev.to/samhartley_dev/i-built-a-morning-briefing-bot-in-50-lines-of-python-heres-why-i-check-telegram-before-email-now-3fhh</guid>
      <description>&lt;h1&gt;
  
  
  I Built a Morning Briefing Bot in 50 Lines of Python — Here's Why I Check Telegram Before Email Now
&lt;/h1&gt;

&lt;p&gt;For years, my morning routine was the same: open laptop, check email, get distracted by Slack, remember I needed to check the weather, forget what I was doing, and 20 minutes later realize I hadn't started actual work yet.&lt;/p&gt;

&lt;p&gt;Sound familiar?&lt;/p&gt;

&lt;p&gt;Three months ago, I built a dead-simple Telegram bot that aggregates everything I actually care about into one message. It fires at 8 AM every day. I read it in 30 seconds. Then I start working.&lt;/p&gt;

&lt;p&gt;No apps to switch between. No rabbit holes. Just one message with the stuff that matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Actually Sends
&lt;/h2&gt;

&lt;p&gt;Every morning at 8 AM, my phone buzzes with something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📅 Morning Brief — Wednesday, Jul 1

Today: Team standup at 10:00, Dentist at 14:30
Tomorrow: Deploy to prod (set reminder!)

🌤️ Weather: 28°C, sunny — no rain expected

💻 Systems: Mac Mini ✅ | GPU Server ✅ | Ubuntu Box ✅
All green. Uptime: 47 days.

📝 Yesterday's notes: "Refactored auth module, tests passing"

⚠️ One thing: GitHub issue #142 still open — "fix API rate limiting"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No graphs. No dashboards. No "click here to see more." Just the facts I need to plan my day.&lt;/p&gt;

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

&lt;p&gt;I already use Telegram for my devops dashboard (wrote about that &lt;a href="https://dev.to/samhartley_dev/i-use-telegram-as-my-devops-dashboard-no-web-ui-no-vpn-just-works-4abc"&gt;here&lt;/a&gt;). Adding a morning briefing was a natural extension.&lt;/p&gt;

&lt;p&gt;But honestly? The real reason is &lt;strong&gt;friction reduction.&lt;/strong&gt; My phone's notification shade is a graveyard of app alerts I ignore. Telegram is one of the few apps I actually open. Putting my briefing there means I actually read it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture (It's Embarrassingly Simple)
&lt;/h2&gt;

&lt;p&gt;Here's the entire stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cron job&lt;/strong&gt; on my Mac Mini — triggers at 8:00 AM daily&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;50-line Python script&lt;/strong&gt; — gathers data from 4 sources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telegram Bot API&lt;/strong&gt; — sends the formatted message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. No web framework. No database. No message queue. Just a script that runs, collects, formats, and sends.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Script
&lt;/h2&gt;

&lt;p&gt;Here's the core of it (simplified, but functional):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;

&lt;span class="c1"&gt;# Config
&lt;/span&gt;&lt;span class="n"&gt;BOT_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;BRIEFING_BOT_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;CHAT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;MY_TELEGRAM_CHAT_ID&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Gather data
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_calendar&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# I export from Apple Calendar to a local ICS file nightly
&lt;/span&gt;    &lt;span class="c1"&gt;# This reads today's events from it
&lt;/span&gt;    &lt;span class="c1"&gt;# ... (parsing logic here) ...
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Team standup at 10:00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Dentist at 14:30&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_weather&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# wttr.in — free, no API key needed
&lt;/span&gt;    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://wttr.in/Sakarya?format=%C+%t&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_system_status&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Quick ping to my other machines
&lt;/span&gt;    &lt;span class="n"&gt;machines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Mac Mini&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;192.168.1.105&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;GPU Server&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;192.168.1.106&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Ubuntu Box&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;192.168.1.100&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;machines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ping -c 1 -W 2 &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;✅&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;❌&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_github_issues&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Check my main repo for open issues labeled "urgent"
&lt;/span&gt;    &lt;span class="c1"&gt;# ... (GitHub API call) ...
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#142: Fix API rate limiting&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Build and send message
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_briefing&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;calendar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_calendar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;weather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_weather&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;systems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_system_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;issues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_github_issues&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%A, %b %d&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;📅 Morning Brief — &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Today:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  • &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;calendar&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;calendar&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  • Nothing scheduled 🎉&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🌤️ Weather: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;💻 Systems:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;systems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
        &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;⚠️ Open issues:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  • &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;issue&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;issue&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://api.telegram.org/bot&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BOT_TOKEN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/sendMessage&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;chat_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CHAT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;parse_mode&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;HTML&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;send_briefing&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The real version has error handling and a few more data sources (like yesterday's git commit summary), but this is the gist. 50 lines. One cron entry. Done.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cron Job
&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;# crontab -e&lt;/span&gt;
0 8 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /usr/bin/python3 /Users/sam/scripts/morning_briefing.py &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/briefing.log 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's literally the entire scheduling infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changed
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt; I'd check 4-5 apps every morning. Sometimes I'd miss something. Sometimes I'd get distracted. Average time to "actually working": 20-30 minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt; One notification. 30 seconds to read. I know what's happening today, whether my systems are healthy, and if there's anything urgent. Then I close Telegram and start work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Average time to "actually working": 2 minutes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The weird part? I feel less anxious. I used to have this low-grade worry that I was forgetting something. Now I know the bot checks for me. If there was a problem, I'd know.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Downsides (Because Nothing's Perfect)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ICS parsing is brittle.&lt;/strong&gt; Apple Calendar exports aren't always clean. I had to add a nightly script that sanitizes the ICS file before the morning run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weather API can be flaky.&lt;/strong&gt; wttr.in is great until it isn't. I added a fallback to a local weather file that updates every hour.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No interactivity.&lt;/strong&gt; It's a one-way push. If I want details ("what's in that GitHub issue?"), I have to go look. I tried adding reply buttons, but honestly, it added complexity I didn't need. The goal was speed, not interactivity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edge cases suck.&lt;/strong&gt; Daylight saving time shift? The cron fired at 7 AM for a week before I noticed. Public holidays? The bot doesn't know. I had to add a manual "skip" flag for vacation days.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should You Build This?
&lt;/h2&gt;

&lt;p&gt;If you check more than 3 apps every morning: probably yes.&lt;/p&gt;

&lt;p&gt;You don't need my exact setup. Use whatever you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Discord webhook&lt;/strong&gt; instead of Telegram?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A simple Bash script&lt;/strong&gt; instead of Python?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;iOS Shortcuts&lt;/strong&gt; instead of cron?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pattern matters more than the stack: &lt;strong&gt;one automated message, curated by you, delivered where you already look.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Start small. My first version just sent the weather and today's calendar. Everything else came later. The 50-line script grew to 150 lines over three months — but it started as a weekend experiment.&lt;/p&gt;

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

&lt;p&gt;I'm experimenting with two additions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Weekly summary on Sundays&lt;/strong&gt; — "This week you shipped 12 commits, closed 3 issues, and your GPU earned $47."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Context-aware alerts&lt;/strong&gt; — If I have a meeting in 15 minutes and haven't checked the briefing, send a nudge. But only for external meetings (not "standup" — I won't forget that).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal isn't to build a product. It's to build a personal utility that removes friction from my day.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I write about running AI locally, building weird automation, and occasionally making money from side projects. If this was useful, drop a comment with your morning routine — I'm always looking for ideas to steal.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>telegram</category>
      <category>automation</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I Rented Out My GPU for Passive Income — Here's What Happened After My First Week</title>
      <dc:creator>Sam Hartley</dc:creator>
      <pubDate>Sat, 27 Jun 2026 08:05:35 +0000</pubDate>
      <link>https://dev.to/samhartley_dev/i-rented-out-my-gpu-for-passive-income-heres-what-happened-after-my-first-week-1mbh</link>
      <guid>https://dev.to/samhartley_dev/i-rented-out-my-gpu-for-passive-income-heres-what-happened-after-my-first-week-1mbh</guid>
      <description>&lt;p&gt;I had an RTX 3060 sitting on a shelf.&lt;/p&gt;

&lt;p&gt;Not broken. Not old. Just... not doing anything. My Windows PC runs models when I need them, but most of the time it's idle. The fans spin, the power draw ticks along, and that 12GB of VRAM just sits there.&lt;/p&gt;

&lt;p&gt;A week ago I connected it to &lt;a href="https://vast.ai" rel="noopener noreferrer"&gt;Vast.ai&lt;/a&gt; — a GPU marketplace where people rent compute time. No code required. You install a daemon, set a price, and wait for someone to rent your machine.&lt;/p&gt;

&lt;p&gt;Here's what actually happened.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Didn't Just Mine Crypto
&lt;/h2&gt;

&lt;p&gt;First thing people ask: "Why not just mine?"&lt;/p&gt;

&lt;p&gt;Short answer: it's 2026, the margins are brutal, and I didn't want to deal with it. GPU compute rental is different — you're renting raw processing power, and the demand right now is AI inference and training. People building LLMs, running diffusion models, doing batch jobs.&lt;/p&gt;

&lt;p&gt;The upside: no mining pool setup, no daily coin price anxiety, no special software. Your machine runs Docker containers, gets paid per second of use, you get a payout.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Setup (Genuinely About 90 Minutes)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Created a Vast.ai account&lt;/li&gt;
&lt;li&gt;Installed the host daemon on Windows (it's a one-click installer)&lt;/li&gt;
&lt;li&gt;Set my RTX 3060 12GB at &lt;strong&gt;$0.15/hour&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Went to bed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. No configuration rabbit holes, no drivers to hunt down. The daemon manages everything — spinning up containers, cleaning up after renters, reporting uptime.&lt;/p&gt;

&lt;p&gt;I set the minimum rental duration to 1 hour so I wouldn't get hit with a dozen 5-minute jobs.&lt;/p&gt;




&lt;h2&gt;
  
  
  The First Week Numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Day&lt;/th&gt;
&lt;th&gt;Hours Rented&lt;/th&gt;
&lt;th&gt;Earnings&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Day 1&lt;/td&gt;
&lt;td&gt;3.2h&lt;/td&gt;
&lt;td&gt;$0.48&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Day 2&lt;/td&gt;
&lt;td&gt;11.5h&lt;/td&gt;
&lt;td&gt;$1.73&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Day 3&lt;/td&gt;
&lt;td&gt;0h&lt;/td&gt;
&lt;td&gt;$0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Day 4&lt;/td&gt;
&lt;td&gt;16.8h&lt;/td&gt;
&lt;td&gt;$2.52&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Day 5&lt;/td&gt;
&lt;td&gt;9.1h&lt;/td&gt;
&lt;td&gt;$1.37&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Day 6&lt;/td&gt;
&lt;td&gt;22.0h&lt;/td&gt;
&lt;td&gt;$3.30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Day 7&lt;/td&gt;
&lt;td&gt;14.4h&lt;/td&gt;
&lt;td&gt;$2.16&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Week 1 total: ~$11.56&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Annualized naively? About $600/year. Which would be great except day 3 was $0 and utilization is inconsistent.&lt;/p&gt;

&lt;p&gt;A more realistic steady-state: &lt;strong&gt;$50–130/month&lt;/strong&gt; depending on demand.&lt;/p&gt;




&lt;h2&gt;
  
  
  What People Actually Rent It For
&lt;/h2&gt;

&lt;p&gt;Vast.ai shows you the jobs (anonymized). Mine has been used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running &lt;code&gt;vllm&lt;/code&gt; inference servers (Mistral, Qwen, LLaMA variants)&lt;/li&gt;
&lt;li&gt;Stable Diffusion batch jobs&lt;/li&gt;
&lt;li&gt;Some kind of PyTorch training run that lasted 8 hours&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 3060 with 12GB VRAM is actually sweet for inference — fits most 7B–13B models at 4-bit quantization without breaking a sweat. It's not the fastest card, but it's affordable to rent, which means demand is there.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Honest Downsides
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;You can't use your GPU while it's rented.&lt;/strong&gt; Sounds obvious, but the practical implication: if you need your machine for local inference and someone's rented it, tough luck. I started routing heavy tasks to my Mac Mini during rental periods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Electricity.&lt;/strong&gt; My RTX 3060 at load pulls about 150W. At Turkish electricity rates, that's roughly $8–15/month in power at typical utilization. So the net is lower than the gross numbers above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's genuinely passive but not predictable.&lt;/strong&gt; Day 3 was $0. Day 6 was near-full utilization. There's no way to forecast demand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Payouts have a minimum.&lt;/strong&gt; Vast.ai pays out once you hit a threshold. Nothing to worry about, just something to know going in.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'm Going to Try Next
&lt;/h2&gt;

&lt;p&gt;The obvious play is adding more GPUs. I have a few more in storage — an RTX 3080 and some older 3060s. If I rack those up, the math gets interesting:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;GPU&lt;/th&gt;
&lt;th&gt;Rate&lt;/th&gt;
&lt;th&gt;Monthly (50% util)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RTX 3060 (current)&lt;/td&gt;
&lt;td&gt;$0.15/h&lt;/td&gt;
&lt;td&gt;~$54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RTX 3080 10GB&lt;/td&gt;
&lt;td&gt;$0.20/h&lt;/td&gt;
&lt;td&gt;~$72&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2x RTX 3070 8GB&lt;/td&gt;
&lt;td&gt;$0.16/h&lt;/td&gt;
&lt;td&gt;~$115&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That's ~$240/month without doing anything after setup. At 70% utilization: ~$340.&lt;/p&gt;

&lt;p&gt;The real work is physical — pulling GPUs from storage, getting them into a rig, managing thermals. But the software side is almost zero maintenance.&lt;/p&gt;




&lt;h2&gt;
  
  
  Should You Try This?
&lt;/h2&gt;

&lt;p&gt;If you have a spare GPU collecting dust: &lt;strong&gt;yes, probably.&lt;/strong&gt; The setup is low friction, the risk is near-zero (worst case, you uninstall the daemon and move on), and even modest earnings beat $0.&lt;/p&gt;

&lt;p&gt;If you're thinking about buying a GPU specifically for this: &lt;strong&gt;do the math carefully.&lt;/strong&gt; At current rates, an RTX 3060 costs ~$300–350 used. Payback period at $50/month is 6–7 months, which is fine — but don't expect to fund your retirement from a single card.&lt;/p&gt;

&lt;p&gt;The real value for me isn't the income (yet). It's that I now have a system running, I understand the demand patterns, and I know the path to scale looks viable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Setup Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Platform: &lt;a href="https://vast.ai" rel="noopener noreferrer"&gt;Vast.ai&lt;/a&gt; (there's also RunPod if you want alternatives)&lt;/li&gt;
&lt;li&gt;Time to set up: ~90 minutes&lt;/li&gt;
&lt;li&gt;Technical skill required: Know how to install software on Windows&lt;/li&gt;
&lt;li&gt;Ongoing maintenance: Almost none&lt;/li&gt;
&lt;li&gt;Realistic earnings: $50–130/month per mid-tier GPU&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy to answer questions if you try this and run into something weird. The daemon is pretty solid but there's always an edge case or two.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I write about running AI locally, automation side projects, and occasionally making money from hardware that would otherwise just collect dust. If any of this is useful, feel free to follow.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Replaced 2.5 Hours of Daily Busywork with a $0 AI Agent Setup</title>
      <dc:creator>Sam Hartley</dc:creator>
      <pubDate>Thu, 25 Jun 2026 08:05:09 +0000</pubDate>
      <link>https://dev.to/samhartley_dev/i-replaced-25-hours-of-daily-busywork-with-a-0-ai-agent-setup-13ad</link>
      <guid>https://dev.to/samhartley_dev/i-replaced-25-hours-of-daily-busywork-with-a-0-ai-agent-setup-13ad</guid>
      <description>&lt;h1&gt;
  
  
  I Replaced 2.5 Hours of Daily Busywork with a $0 AI Agent Setup
&lt;/h1&gt;

&lt;p&gt;Three months ago I was spending almost three hours a day on tasks a script could do. Email triage, inbox checks, calendar reminders, weather lookups, market data refreshes. Nothing creative. Nothing that needed my brain. Just... mechanical.&lt;/p&gt;

&lt;p&gt;I didn't want another SaaS subscription. I didn't want to glue together Zapier and Notion and hope it worked. I wanted something I owned, running on hardware I already had, costing me nothing after setup.&lt;/p&gt;

&lt;p&gt;So I built it. And it actually works.&lt;/p&gt;

&lt;p&gt;Here's what I automated, how I built it, and what broke along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Was Doing Every Day (That I Don't Do Anymore)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Check 3 email accounts for urgent stuff&lt;/td&gt;
&lt;td&gt;~25 min&lt;/td&gt;
&lt;td&gt;Agent alerts me only when something matters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fiverr inbox — new inquiries + scams&lt;/td&gt;
&lt;td&gt;~20 min&lt;/td&gt;
&lt;td&gt;Hourly scan, instant Telegram notification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Calendar — what's happening today?&lt;/td&gt;
&lt;td&gt;~10 min&lt;/td&gt;
&lt;td&gt;Morning summary at 9 AM, prep alerts 30 min before&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weather check before leaving&lt;/td&gt;
&lt;td&gt;~5 min&lt;/td&gt;
&lt;td&gt;Agent tells me if I need an umbrella&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Market data for my watch face&lt;/td&gt;
&lt;td&gt;~15 min&lt;/td&gt;
&lt;td&gt;Live data every 15 min, zero interaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code review on my own repos&lt;/td&gt;
&lt;td&gt;~45 min&lt;/td&gt;
&lt;td&gt;Automated PR summaries in 12 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Total: ~2 hours 40 minutes → ~10 minutes of actual attention&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The 10 minutes is me reading alerts and deciding what to do. The agent doesn't make decisions. It surfaces information.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hardware
&lt;/h2&gt;

&lt;p&gt;Everything runs on a Mac Mini M4 I already owned. No cloud VMs, no rented GPUs for this part.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mac Mini M4 (always on, ~8W idle)
├── Ollama (local LLM)
│   ├── qwen3.5:9b — general reasoning
│   └── qwen3-coder:30b — code analysis (via network GPU)
├── Python scripts + cron jobs
├── Telegram Bot API — notifications
└── Background services (Garmin updater, health checks)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Monthly cost for the AI layer: &lt;strong&gt;$0&lt;/strong&gt;. The Mac Mini was already running 24/7 for other projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "AI Agent" Actually Means Here
&lt;/h2&gt;

&lt;p&gt;Let's be honest: "AI agent" is an overused term. What I built is a collection of Python scripts that use a local LLM for the parts that need understanding, and plain old regex/cron for everything else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The agent isn't one thing. It's a system:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scheduler&lt;/strong&gt; (cron) — triggers tasks at intervals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Perception layer&lt;/strong&gt; — scripts that fetch data (email, Fiverr, weather, calendar)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning layer&lt;/strong&gt; — local LLM decides if something is worth alerting about&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action layer&lt;/strong&gt; — sends me a Telegram message&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. No autonomous web browsing. No decision-making without my input. Just: see → understand → tell me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fiverr Inbox Monitor (My Favorite Example)
&lt;/h2&gt;

&lt;p&gt;I sell automation services on Fiverr. Checking the inbox was eating 20 minutes a day. Worse: half the messages were scams ("contact me on WhatsApp for big project").&lt;/p&gt;

&lt;p&gt;My agent now:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Opens a headless browser session every hour&lt;/li&gt;
&lt;li&gt;Reads new messages&lt;/li&gt;
&lt;li&gt;Runs each through a local LLM with this prompt:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Is this a legitimate business inquiry or a scam?
   Scam indicators: external contact requests, generic greeting + immediate project offer,
   poor grammar with urgent tone, requests to communicate off-platform.

   Message: {message_text}

   Respond: LEGITIMATE or SCAM with one-sentence reasoning.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;If legitimate → instant Telegram alert with message preview&lt;/li&gt;
&lt;li&gt;If scam → logged silently, no alert&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Results after 3 months:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;100% scam detection rate (verified manually afterward)&lt;/li&gt;
&lt;li&gt;0 false positives&lt;/li&gt;
&lt;li&gt;~10 hours/month saved&lt;/li&gt;
&lt;li&gt;I reply to real customers faster because I'm not wading through garbage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The LLM handles the nuance. Regex would miss edge cases. A human would get bored and slip up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Didn't Use the Cloud
&lt;/h2&gt;

&lt;p&gt;I have API keys for OpenAI, Anthropic, and Google. I use them for complex reasoning tasks. But for automation?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost math:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local Qwen 3.5 9B: $0 per query, ~2 seconds response&lt;/li&gt;
&lt;li&gt;GPT-4o-mini: $0.00015 per 1K tokens&lt;/li&gt;
&lt;li&gt;20 queries/day × 30 days × 500 tokens = ~$4.50/month&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's not nothing for a side project. But more importantly: &lt;strong&gt;latency&lt;/strong&gt;. Local inference is faster for simple tasks, doesn't need internet, and doesn't send my emails/Fiverr messages to a third party.&lt;/p&gt;

&lt;p&gt;The cloud is my fallback for tasks the 9B model can't handle. Maybe 5% of queries.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Broke (And What I Fixed)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Week 1:&lt;/strong&gt; The Fiverr login session expired after 48 hours. I was running headless Chrome with saved cookies. Fiverr's session management is aggressive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Switched to Safari with AppleScript automation. No session issues since — Apple's keychain handles authentication transparently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 2:&lt;/strong&gt; Alert fatigue. I set the agent to notify on &lt;em&gt;every&lt;/em&gt; email. Bad idea.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Two-tier system. "Urgent" alerts (from known contacts, specific keywords) → instant notification. "Everything else" → digest at 9 AM and 6 PM. Unsubscribe-style filtering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 3:&lt;/strong&gt; The weather API I was using (free tier) rate-limited me.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Added a fallback chain. Primary → wttr.in → OpenWeatherMap (rarely hit). The agent doesn't care which source works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Month 2:&lt;/strong&gt; LLM started hallucinating calendar events that didn't exist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Added validation layer. LLM extracts event details → script queries the actual calendar API → confirms before alerting. LLM suggests, system verifies.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code (The Interesting Parts)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Core Orchestrator (simplified)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Main agent loop — runs every hour via cron&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;schedule&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;email_agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fiverr_agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;calendar_agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weather_agent&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;notifier&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;telegram_alert&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_all_checks&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Run all agents and collect alerts&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;alerts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="c1"&gt;# Each agent returns (alert_text, priority) or None
&lt;/span&gt;    &lt;span class="n"&gt;alerts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;alerts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fiverr_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;alerts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calendar_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;alerts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weather_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="c1"&gt;# Send urgent immediately, batch low-priority
&lt;/span&gt;    &lt;span class="n"&gt;urgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;alerts&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;urgent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;alerts&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;normal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;urgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;telegram_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;digest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;📊 Agent Digest&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="nf"&gt;telegram_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;normal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Cron runs this script hourly
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;run_all_checks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  LLM Decision Layer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;should_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Use local LLM to decide if an email warrants immediate notification&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;You are an email triage assistant. Analyze this email:

    From: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;email_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sender&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
    Subject: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;email_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;subject&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
    Preview: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;email_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;preview&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

    Rules:
    - ALERT if: from known contact, contains &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;urgent/meeting/action required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
      payment-related, or from a service I actively use
    - SILENT if: newsletter, promotional, automated notification,
      no action needed

    Respond ONLY with: ALERT: [reason] or SILENT: [reason]&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5:9b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;is_alert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ALERT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;reason&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No reason given&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;is_alert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Notification Script
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# notify.sh — called by any agent&lt;/span&gt;

&lt;span class="nv"&gt;BOT_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;
&lt;span class="nv"&gt;CHAT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;
&lt;span class="nv"&gt;MESSAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;PRIORITY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;normal&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.telegram.org/bot&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BOT_TOKEN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/sendMessage"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;chat_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CHAT_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MESSAGE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;parse_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"HTML"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What I Didn't Automate (And Won't)
&lt;/h2&gt;

&lt;p&gt;The agent is &lt;em&gt;informational&lt;/em&gt;, not &lt;em&gt;autonomous&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I don't let it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reply to emails or Fiverr messages (too risky — one bad response destroys trust)&lt;/li&gt;
&lt;li&gt;Make calendar changes (I'll review and confirm)&lt;/li&gt;
&lt;li&gt;Access financial accounts or make transactions&lt;/li&gt;
&lt;li&gt;Post on social media (I've seen automated tweets go very wrong)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The rule:&lt;/strong&gt; The agent tells me what I need to know. I decide what to do. This isn't laziness — it's risk management. AI is excellent at detection, mediocre at judgment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Months In: The Real Impact
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time saved:&lt;/strong&gt; ~2.5 hours/day = ~75 hours/month. That's almost two full work weeks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I did with the time:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built a Garmin watch face with live crypto charts (side project)&lt;/li&gt;
&lt;li&gt;Started GPU rental as passive income (another side project)&lt;/li&gt;
&lt;li&gt;Actually took a weekend off without checking email every hour&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Unexpected benefit:&lt;/strong&gt; I make better decisions because I'm not decision-fatigued. When you've already spent mental energy on inbox triage, your judgment on actual work suffers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; $0 for AI, ~12 hours initial setup, ~30 minutes/week maintenance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should You Build This?
&lt;/h2&gt;

&lt;p&gt;If you're spending &amp;gt;1 hour/day on mechanical tasks: probably yes.&lt;/p&gt;

&lt;p&gt;If you're expecting a magic "AI agent" that runs your life: no. This is scripting with a smart layer on top. The LLM handles ambiguity. Everything else is just... code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start with one task.&lt;/strong&gt; Get it reliable. Add the next. I began with just email triage. Two weeks later I added Fiverr. Then calendar. Then weather. Each one took an evening.&lt;/p&gt;

&lt;p&gt;The compound effect is what matters.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I write about building automation systems that actually work — local AI, self-hosted tools, and side projects that make money while you sleep.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;→ &lt;a href="http://www.fiverr.com/s/XLyg" rel="noopener noreferrer"&gt;Check out my automation work on Fiverr&lt;/a&gt;&lt;br&gt;
→ &lt;a href="https://t.me/celebibot_en" rel="noopener noreferrer"&gt;Follow CelebiBots on Telegram&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>productivity</category>
      <category>agents</category>
    </item>
    <item>
      <title>I Built an AI Content Team That Posts to My Blog While I Sleep</title>
      <dc:creator>Sam Hartley</dc:creator>
      <pubDate>Tue, 23 Jun 2026 08:04:44 +0000</pubDate>
      <link>https://dev.to/samhartley_dev/i-built-an-ai-content-team-that-posts-to-my-blog-while-i-sleep-24bk</link>
      <guid>https://dev.to/samhartley_dev/i-built-an-ai-content-team-that-posts-to-my-blog-while-i-sleep-24bk</guid>
      <description>&lt;p&gt;I used to write blog posts the old way. Open a blank page. Stare at it. Write something. Rewrite it three times. Publish. Repeat every two weeks when I remembered to do it.&lt;/p&gt;

&lt;p&gt;Now I have a system that writes and publishes for me. Not a spam bot. Not auto-generated garbage. Actual technical articles in my voice, posted on a schedule, while I'm doing something else.&lt;/p&gt;

&lt;p&gt;Here's the honest breakdown of how it works, what it costs, and where it falls apart.&lt;/p&gt;

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

&lt;p&gt;I've been running a few side projects for a while now — a GPU rental setup, some Telegram bots, a Garmin watch face. Every few months I'd think "I should write about this" and then... not do it. The gap between "built something cool" and "published an article about it" was basically infinite.&lt;/p&gt;

&lt;p&gt;I tried content calendars. Reminder apps. The usual productivity hacks. None of them stuck because writing is work, and work needs time I wasn't willing to consistently allocate.&lt;/p&gt;

&lt;p&gt;So I asked myself: what if the system didn't just remind me to write — what if it actually wrote?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture (No Hype, Just Scripts)
&lt;/h2&gt;

&lt;p&gt;The setup is three components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Topic selection&lt;/strong&gt; — a rotating list of drafts and ideas, picked by a simple rule (oldest first, or whatever I'm excited about)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writing agent&lt;/strong&gt; — a local LLM (Qwen 3 Coder 30B on my RTX 3060) that takes a topic + my notes and produces a first draft&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publishing agent&lt;/strong&gt; — a cron job that posts to Dev.to via API when an article is ready&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. No orchestration framework, no LangChain pipeline, no vector store for "content strategy." Just scripts, cron, and an LLM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic Queue (markdown files)
  → Pick next topic
  → LLM writes draft (in my voice, from my notes)
  → I review and edit (takes 10-15 min)
  → Publish via Dev.to API
  → Notify me with the link
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Writing Process
&lt;/h2&gt;

&lt;p&gt;The key detail: the LLM doesn't write from scratch. It writes from my notes.&lt;/p&gt;

&lt;p&gt;Each article topic has a markdown file with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What I built&lt;/li&gt;
&lt;li&gt;The actual architecture&lt;/li&gt;
&lt;li&gt;Numbers (costs, earnings, time spent)&lt;/li&gt;
&lt;li&gt;My honest opinion on what worked and what didn't&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The LLM takes those rough notes and turns them into something readable. It's not creative — it's structural. It takes my bullet points and makes them flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; My notes for this article literally looked like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Problem: don't write consistently
- Solution: AI writes drafts from my notes
- Architecture: cron + LLM + Dev.to API
- Honest part: still need to review, not fully hands-off
- Cost: $0 (local LLM)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The LLM expanded that into what you're reading now. I spent 12 minutes editing it. That's the actual time savings.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Articles Look Like
&lt;/h2&gt;

&lt;p&gt;I have a few rules the system follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Personal voice&lt;/strong&gt; — first person, casual, not corporate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specific numbers&lt;/strong&gt; — real costs, real earnings, real time spent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Honest downsides&lt;/strong&gt; — if something is annoying, say so&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code examples&lt;/strong&gt; — actual working scripts, not pseudocode&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No clickbait&lt;/strong&gt; — the title should describe the article&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result? Articles that read like I wrote them, because fundamentally I did. The LLM is just the typist.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Schedule
&lt;/h2&gt;

&lt;p&gt;Every two days, the system picks a topic and produces a draft. I get a notification with a link to review it. If I'm busy, I skip it and it moves to the next topic. If I have 15 minutes, I edit and approve.&lt;/p&gt;

&lt;p&gt;The publishing happens automatically after approval.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In practice:&lt;/strong&gt; about 60% of drafts get published on schedule. The other 40% I either skip because the topic feels stale, or I rewrite heavily because the LLM missed the point.&lt;/p&gt;

&lt;p&gt;It's not fully autonomous and I don't want it to be. The human-in-the-loop is the safety rail.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cost
&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;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LLM (local Ollama)&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dev.to API&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;My time per article&lt;/td&gt;
&lt;td&gt;~15 min (editing)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;My time before (full write)&lt;/td&gt;
&lt;td&gt;~2-3 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That's roughly a 10x time savings per article. At 15 articles per month, that's 30-40 hours of writing time I don't spend.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Breaks
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The LLM hallucinates my numbers.&lt;/strong&gt; If I don't include exact figures in the notes, it'll make up something plausible-sounding. I caught it claiming "$240/month GPU earnings" when the real number was closer to $50. Always verify the numbers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Voice drift.&lt;/strong&gt; After a few articles, the LLM starts sounding more generic. I fix this by including snippets from previous articles in the prompt as "examples of my style."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scheduling conflicts.&lt;/strong&gt; If I approve two articles for the same day, the Dev.to API rejects the second (rate limiting). The system now enforces a minimum 48-hour gap between posts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Topic exhaustion.&lt;/strong&gt; I have maybe 20 solid topics in my queue. At one post every two days, that's 40 days of content. Then I need to actually build more things worth writing about. The system can't manufacture experiences — only document them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Works (For Me)
&lt;/h2&gt;

&lt;p&gt;I'm not trying to build a content empire. I don't want to game algorithms or go viral. I just want a consistent record of what I'm building, written in my voice, published somewhere people can find it.&lt;/p&gt;

&lt;p&gt;This system does that. It doesn't replace me — it removes the friction between having something to say and actually saying it.&lt;/p&gt;

&lt;p&gt;The articles are still mine. The ideas are mine. The code is mine. The LLM just handles the part I find tedious: turning rough thoughts into readable prose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should You Build This?
&lt;/h2&gt;

&lt;p&gt;If you have a bunch of half-written drafts and a notes folder full of project ideas: &lt;strong&gt;probably yes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you don't already have raw material (notes, numbers, experiences): &lt;strong&gt;no.&lt;/strong&gt; An LLM can't write your blog for you if you have nothing to say. It can only help you say it faster.&lt;/p&gt;

&lt;p&gt;The real requirement isn't technical skill — it's having something worth writing about in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup in One File
&lt;/h2&gt;

&lt;p&gt;If you want to try this, here's the core of it:&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;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# publish-article.sh&lt;/span&gt;

&lt;span class="nv"&gt;API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_dev_to_api_key"&lt;/span&gt;
&lt;span class="nv"&gt;ARTICLE_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Read markdown content&lt;/span&gt;
&lt;span class="nv"&gt;CONTENT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ARTICLE_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Extract title from frontmatter&lt;/span&gt;
&lt;span class="nv"&gt;TITLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CONTENT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"^title:"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/title: //'&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'"'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Post to Dev.to&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://dev.to/api/articles &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"api-key: &lt;/span&gt;&lt;span class="nv"&gt;$API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"{
    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;article&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: {
      &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$TITLE&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,
      &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;body_markdown&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CONTENT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;-Rs&lt;/span&gt; .&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;,
      &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;published&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true,
      &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;tags&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: [&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;ai&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;automation&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;side-project&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;]
    }
  }"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a cron job every 2 days, a folder of drafts, and you're 90% there.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I write about building things with AI, running hardware at home, and the occasional side project that makes a little money. If any of this is useful, feel free to follow along.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;→ &lt;a href="http://www.fiverr.com/s/XLyg" rel="noopener noreferrer"&gt;Custom automation setups on Fiverr&lt;/a&gt;&lt;br&gt;
→ &lt;a href="https://t.me/celebibot_en" rel="noopener noreferrer"&gt;Follow CelebiBots on Telegram&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  ai #automation #contentcreation #sideproject #buildinginpublic
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>productivity</category>
      <category>ollama</category>
    </item>
    <item>
      <title>I Ditched 5 Cloud Subscriptions and Built a Self-Hosted Stack — Here's the Real Cost Breakdown</title>
      <dc:creator>Sam Hartley</dc:creator>
      <pubDate>Sun, 21 Jun 2026 08:01:27 +0000</pubDate>
      <link>https://dev.to/samhartley_dev/i-ditched-5-cloud-subscriptions-and-built-a-self-hosted-stack-heres-the-real-cost-breakdown-4jma</link>
      <guid>https://dev.to/samhartley_dev/i-ditched-5-cloud-subscriptions-and-built-a-self-hosted-stack-heres-the-real-cost-breakdown-4jma</guid>
      <description>&lt;p&gt;Last year I was paying $89/month for cloud services I didn't fully control. Notion, Slack, GitHub Copilot, a VPS, and a managed database. Each one seemed cheap individually. Together they were a quiet drain.&lt;/p&gt;

&lt;p&gt;Then I looked at the hardware I already owned. A Mac Mini M4 running 24/7. A Windows PC with GPUs that was idle half the day. An old Ubuntu box from a previous project. I was paying for cloud convenience while sitting on local capacity.&lt;/p&gt;

&lt;p&gt;So I migrated everything. Not because I'm anti-cloud or a privacy maximalist — I'm neither. I just got curious whether I could match the functionality for less money, and what the tradeoffs would actually feel like.&lt;/p&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cloud Service&lt;/th&gt;
&lt;th&gt;Monthly Cost&lt;/th&gt;
&lt;th&gt;Self-Hosted Replacement&lt;/th&gt;
&lt;th&gt;Runs On&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Notion ($8/mo personal plan)&lt;/td&gt;
&lt;td&gt;$8&lt;/td&gt;
&lt;td&gt;Obsidian + local Git sync&lt;/td&gt;
&lt;td&gt;Mac Mini&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slack (free tier, limited history)&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;Mattermost&lt;/td&gt;
&lt;td&gt;Ubuntu box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Copilot&lt;/td&gt;
&lt;td&gt;$10&lt;/td&gt;
&lt;td&gt;Ollama + Continue.dev extension&lt;/td&gt;
&lt;td&gt;Windows PC (RTX 3060)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DigitalOcean VPS ($6 droplet)&lt;/td&gt;
&lt;td&gt;$6&lt;/td&gt;
&lt;td&gt;Docker + Nginx on Mac Mini&lt;/td&gt;
&lt;td&gt;Mac Mini&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supabase (free tier, 500MB)&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;PostgreSQL in Docker&lt;/td&gt;
&lt;td&gt;Mac Mini&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$24&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0 ongoing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Wait, that's only $24. Where did I get $89? There were three more services I also cut that weren't directly replaceable: a $15/mo analytics tool, a $20/mo newsletter platform, and a $30/mo CI/CD runner. I stopped using those entirely rather than self-hosting equivalents. My actual stack shrank, which is a different kind of saving.&lt;/p&gt;

&lt;p&gt;The point: I wasn't just replacing services. I was questioning whether I needed them at all.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Notes &amp;amp; Documentation: Obsidian + Git
&lt;/h3&gt;

&lt;p&gt;Notion is excellent. I used it for two years. But I never used the databases, the formulas, the relations. I used it as a markdown editor with folders. That's exactly what Obsidian is, except your files live on your disk as plain Markdown.&lt;/p&gt;

&lt;p&gt;My setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Obsidian desktop app on Mac and Windows&lt;/li&gt;
&lt;li&gt;Vault stored in &lt;code&gt;~/notes/&lt;/code&gt; on the Mac Mini&lt;/li&gt;
&lt;li&gt;Synced to the Windows PC via a bare Git repo over local network&lt;/li&gt;
&lt;li&gt;No cloud sync service involved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Git sync runs every hour via cron. It's not instant like Notion, but my notes don't need to be real-time. If I'm on the Windows PC and need a note from the Mac, I pull. Takes 2 seconds.&lt;/p&gt;

&lt;p&gt;Tradeoff: No mobile app access when I'm away from home. I accepted this. 90% of my note-taking happens at my desk anyway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Team Chat: Mattermost
&lt;/h3&gt;

&lt;p&gt;I don't have a team. I have one collaborator on a side project and a couple of friends who help test things. Slack's free tier deletes messages after 90 days, which is annoying when you're debugging something from three months ago.&lt;/p&gt;

&lt;p&gt;Mattermost runs in Docker on the Ubuntu box. It took 20 minutes to set up with Docker Compose. It has channels, threads, file uploads, and webhooks. Everything I actually used in Slack.&lt;/p&gt;

&lt;p&gt;Tradeoff: No Slack Connect, no huddles, no third-party app directory. I don't need any of those. If I did, this replacement wouldn't work.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Coding Assistant: Ollama + Continue.dev
&lt;/h3&gt;

&lt;p&gt;GitHub Copilot is genuinely good. I used it for a year. But I was already running local models for other tasks, and I started wondering whether a local Qwen 3 Coder 30B could match it.&lt;/p&gt;

&lt;p&gt;Short answer: for autocomplete and simple generation, yes. For complex multi-file reasoning, Copilot is still better. But Continue.dev lets me switch models on the fly, and I've found that 80% of my coding assistance needs are simple enough for the local model.&lt;/p&gt;

&lt;p&gt;The setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ollama on the Windows PC (RTX 3060, 12GB VRAM)&lt;/li&gt;
&lt;li&gt;Qwen 3 Coder 30B for generation&lt;/li&gt;
&lt;li&gt;DeepSeek R1 8B for reasoning tasks&lt;/li&gt;
&lt;li&gt;Continue.dev extension in Windsurf&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tradeoff: Slower. Copilot suggestions appear in under a second. My local setup takes 3-5 seconds for the 30B model. I adjusted my workflow to accept the delay — I hit tab less impulsively and think slightly more before requesting completions.&lt;/p&gt;

&lt;h3&gt;
  
  
  VPS Replacement: Docker + Nginx on the Mac Mini
&lt;/h3&gt;

&lt;p&gt;I had a $6 DigitalOcean droplet running a few small services: a webhook receiver, a file server, and a reverse proxy for internal tools. Nothing that needed real horsepower.&lt;/p&gt;

&lt;p&gt;The Mac Mini is already on 24/7 for my AI agents and cron jobs. Adding Docker and Nginx to it was trivial. It handles the same load with resources to spare.&lt;/p&gt;

&lt;p&gt;I exposed it via Cloudflare Tunnel (free tier), so I don't need to open ports on my router or deal with dynamic DNS.&lt;/p&gt;

&lt;p&gt;Tradeoff: If my home internet goes down, these services go down. The droplet never did. But my home internet has been stable for months, and the services aren't critical enough to warrant $6/month insurance against a rare outage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database: PostgreSQL in Docker
&lt;/h3&gt;

&lt;p&gt;Supabase's free tier is generous but limited. I hit the 500MB cap twice and had to prune data. Self-hosting PostgreSQL in Docker gives me as much storage as my disk allows.&lt;/p&gt;

&lt;p&gt;I use it for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agent memory logs&lt;/li&gt;
&lt;li&gt;Telegram bot state&lt;/li&gt;
&lt;li&gt;Fiverr order tracking&lt;/li&gt;
&lt;li&gt;Personal analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's not highly available, not backed up to the cloud, and not magically scalable. It's just a database that stores data and answers queries. For my use case, that's enough.&lt;/p&gt;

&lt;p&gt;Tradeoff: I back up the data directory to an external drive weekly. If the Mac Mini dies, I lose up to a week of non-critical data. I can live with that.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Actually Costs
&lt;/h2&gt;

&lt;p&gt;The cloud services cost $24/month ($288/year). The self-hosted stack costs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Electricity (Mac Mini 24/7)&lt;/td&gt;
&lt;td&gt;~$3/month&lt;/td&gt;
&lt;td&gt;~20W idle, measured with a smart plug&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Electricity (Ubuntu box, always on)&lt;/td&gt;
&lt;td&gt;~$5/month&lt;/td&gt;
&lt;td&gt;~35W, older hardware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Initial hardware&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;Already owned&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloudflare Tunnel&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;Free tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$8/month&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So I save about $16/month. Not life-changing money. But over a year that's $192, and more importantly, I own the stack. No pricing changes. No feature removals. No "we've updated our terms of service."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Benefits (Beyond Money)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Latency.&lt;/strong&gt; My internal tools respond instantly because they're on my LAN. The webhook receiver used to take 200ms from the VPS. Now it takes 5ms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Privacy.&lt;/strong&gt; My notes, chat history, and database are on my hardware. Not because I'm hiding anything, but because it's nobody's business what side projects I'm building.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customization.&lt;/strong&gt; When I wanted to add a custom webhook endpoint that formatted data specifically for my Telegram bots, I just wrote a Python script and dropped it in the Nginx config. No vendor limitations, no API quotas.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Downsides (Honest)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Maintenance burden.&lt;/strong&gt; When PostgreSQL had a disk space issue last month, I had to fix it myself. No support ticket to open. I spent an evening reading Docker logs and pruning old backups.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No mobile access to notes.&lt;/strong&gt; This genuinely bothers me sometimes. I keep a small notebook app on my phone for quick captures, then transfer to Obsidian later. It's friction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backup anxiety.&lt;/strong&gt; I back up to an external drive, but what if the house burns down? I've started syncing critical data to a cheap Hetzner storage box ($3/month) as off-site backup. So I'm not fully cloud-free after all — just selective about what needs redundancy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slower AI completions.&lt;/strong&gt; I mentioned this above. It's real. There are moments where I miss Copilot's instant suggestions, especially when I'm tired and want the machine to think for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Shouldn't Do This
&lt;/h2&gt;

&lt;p&gt;If you're on a team of more than three people, use the tools your team knows. If you need 99.99% uptime, pay for it. If you value your time at more than $50/hour and this migration would take you a weekend, it's probably not worth it financially.&lt;/p&gt;

&lt;p&gt;I did this because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'm a solo developer with full control over my stack&lt;/li&gt;
&lt;li&gt;I already owned the hardware&lt;/li&gt;
&lt;li&gt;I find this stuff genuinely interesting (if you don't, it'll feel like chores)&lt;/li&gt;
&lt;li&gt;My requirements are simple enough to match with open-source tools&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Self-hosting isn't about sticking it to Big Tech or achieving digital purity. It's about matching your tools to your actual needs instead of paying for features you'll never use.&lt;/p&gt;

&lt;p&gt;I'm not fully cloud-free. I still use GitHub, Cloudflare, and that Hetzner backup. The goal isn't ideological — it's practical. Pay for what you need. Run what you can. Question everything in between.&lt;/p&gt;

&lt;p&gt;If you're curious about one specific replacement, drop a comment and I'll write a detailed setup guide for that piece.&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>devops</category>
      <category>productivity</category>
      <category>cost</category>
    </item>
    <item>
      <title>I Gave Each of My AI Agents a Personality — Here's Why My Workflow Actually Improved</title>
      <dc:creator>Sam Hartley</dc:creator>
      <pubDate>Fri, 19 Jun 2026 08:01:30 +0000</pubDate>
      <link>https://dev.to/samhartley_dev/i-gave-each-of-my-ai-agents-a-personality-heres-why-my-workflow-actually-improved-2dl9</link>
      <guid>https://dev.to/samhartley_dev/i-gave-each-of-my-ai-agents-a-personality-heres-why-my-workflow-actually-improved-2dl9</guid>
      <description>&lt;p&gt;I used to have one AI assistant. It did everything — coded, wrote docs, answered questions, monitored my inbox.&lt;/p&gt;

&lt;p&gt;It was fine. But "fine" isn't the same as "good." One model trying to be a generalist meant it was mediocre at everything. Context bloat. Conflicting instructions. The coding advice was too cautious. The writing was too robotic. The inbox monitoring missed nuance because the model was busy trying to remember my entire codebase.&lt;/p&gt;

&lt;p&gt;So I split it into three. Each with a different personality, different model, different job. And it actually works better.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with One Agent to Rule Them All
&lt;/h2&gt;

&lt;p&gt;When you have one AI doing everything, you run into three problems fast:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Context pollution.&lt;/strong&gt; The coding instructions leak into the writing tone. The writing style bleeds into the code suggestions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Wrong tool for the job.&lt;/strong&gt; A 70B parameter model is overkill for "check my calendar." A 7B model is underpowered for "refactor this 500-line function."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. No specialization.&lt;/strong&gt; My coding agent doesn't need to know my grocery list. My writing agent doesn't need to know my API keys. But when there's only one context window, everything is in there.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three-Agent Setup
&lt;/h2&gt;

&lt;p&gt;I now run three distinct agents, each with its own model, personality, and scope:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Personality&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Celebi&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Qwen 3.5 9B (Mac Mini)&lt;/td&gt;
&lt;td&gt;Generalist, casual, resourceful&lt;/td&gt;
&lt;td&gt;Orchestration, daily checks, notifications, routing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ProgrammierMinna&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Qwen 3 Coder 30B (RTX 3060)&lt;/td&gt;
&lt;td&gt;Precise, technical, no fluff&lt;/td&gt;
&lt;td&gt;Code generation, debugging, refactoring, PR review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DocMinna&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Granite 3.2 8B (Mac Mini)&lt;/td&gt;
&lt;td&gt;Formal, structured, thorough&lt;/td&gt;
&lt;td&gt;Documentation, technical writing, READMEs, specs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Why Different Models?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Celebi runs on the Mac Mini (M4)&lt;/strong&gt; because it's always on, low power, and handles simple tasks instantly. Qwen 3.5 9B is perfect for "check my email, summarize it, tell me if it's urgent."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ProgrammierMinna runs on the RTX 3060&lt;/strong&gt; because coding tasks need a bigger model. Qwen 3 Coder 30B actually understands large codebases, suggests proper refactors, and catches edge cases the 9B misses. Response time is 10-15 seconds — fine for code, too slow for "what's the weather."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DocMinna also runs on the Mac Mini&lt;/strong&gt; with Granite 3.2 8B. It's smaller because documentation doesn't need frontier reasoning. It just needs to be structured, consistent, and technically accurate. The smaller model is faster and cheaper.&lt;/p&gt;

&lt;h2&gt;
  
  
  How They Talk to Each Other
&lt;/h2&gt;

&lt;p&gt;This was the hard part. I didn't want three separate chat windows. I wanted one interface (Telegram) where I message Celebi, and Celebi delegates to the right specialist.&lt;/p&gt;

&lt;p&gt;Here's how it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User (Telegram): "Refactor the auth module in project X"
  → Celebi receives message
  → Classifies: "coding task, complex"
  → Routes to ProgrammierMinna
  → ProgrammierMinna generates refactored code
  → Returns to Celebi
  → Celebi formats response and sends back to user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user never talks directly to ProgrammierMinna or DocMinna. Celebi is the router. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The user has one interface&lt;/li&gt;
&lt;li&gt;Each specialist gets only relevant context&lt;/li&gt;
&lt;li&gt;Results are combined and formatted consistently&lt;/li&gt;
&lt;li&gt;If a task is simple, Celebi handles it directly (no delegation overhead)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What "Personality" Actually Means in Practice
&lt;/h2&gt;

&lt;p&gt;I don't mean "quirky chatbot with a backstory." I mean three things:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Different System Prompts
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Celebi:&lt;/strong&gt; "You're a resourceful assistant. Be concise. Don't ask clarifying questions unless critical. Default to action."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ProgrammierMinna:&lt;/strong&gt; "You're a senior software engineer. Write clean, maintainable code. Add error handling. Consider edge cases. Explain your reasoning briefly."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DocMinna:&lt;/strong&gt; "You're a technical writer. Structure docs with clear headings. Include code examples. Write for an intermediate developer. Be thorough but not verbose."&lt;/p&gt;

&lt;p&gt;These aren't decorations — they fundamentally change the output. The same request to all three produces completely different results.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Different Context Scopes
&lt;/h3&gt;

&lt;p&gt;Celebi sees my calendar, emails, weather, and general notes. It knows I'm in Turkey, that I have a meeting at 3 PM, that it's hot outside.&lt;/p&gt;

&lt;p&gt;ProgrammierMinna sees my Git repos, code patterns, and project structure. It knows I prefer Go over Python for CLI tools, that I use specific naming conventions, that I hate nested callbacks.&lt;/p&gt;

&lt;p&gt;DocMinna sees my documentation templates, style guides, and existing docs. It knows I write in Markdown, that I include a "Quick Start" section, that I don't use emojis in technical docs.&lt;/p&gt;

&lt;p&gt;Each agent's context is &lt;strong&gt;filtered.&lt;/strong&gt; Celebi doesn't get the Git repos. ProgrammierMinna doesn't get my grocery list. This alone cut my token usage by ~40%.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Different Tone and Format
&lt;/h3&gt;

&lt;p&gt;Ask all three to "explain Docker":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Celebi:&lt;/strong&gt; "Docker packages apps into containers so they run the same everywhere. Think of it as a shipping container for software — standardized, portable, isolated. Need help with a specific setup?"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ProgrammierMinna:&lt;/strong&gt; "Docker uses OS-level virtualization to package applications with their dependencies. Key concepts: images (read-only templates), containers (runtime instances), and Dockerfiles (build instructions). For multi-container apps, use Docker Compose. Here's a minimal example..."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DocMinna:&lt;/strong&gt; "Docker is a platform for developing, shipping, and running applications in containers. This guide covers installation, core concepts (images, containers, volumes), and best practices for production deployments..."&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same facts. Completely different delivery. And that's the point — you pick the right voice for the situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Routing Logic
&lt;/h2&gt;

&lt;p&gt;Celebi decides who handles what. The rules are simple but effective:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input Signal&lt;/th&gt;
&lt;th&gt;Route To&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Contains code snippets, "refactor," "debug," "function"&lt;/td&gt;
&lt;td&gt;ProgrammierMinna&lt;/td&gt;
&lt;td&gt;"Fix this Go error"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contains "document," "README," "spec," "guide"&lt;/td&gt;
&lt;td&gt;DocMinna&lt;/td&gt;
&lt;td&gt;"Write API docs for this endpoint"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;General question, scheduling, notification&lt;/td&gt;
&lt;td&gt;Celebi (self)&lt;/td&gt;
&lt;td&gt;"What's on my calendar?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mixed task (code + docs)&lt;/td&gt;
&lt;td&gt;Both, combined&lt;/td&gt;
&lt;td&gt;"Build a tool and document it"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The routing is a lightweight classifier — just a few-shot prompt to Qwen 3.5 9B. It gets it right ~95% of the time. The 5% that are wrong? I correct it, and the model learns from the feedback (stored in memory files).&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Improved
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Code quality:&lt;/strong&gt; ProgrammierMinna suggests better abstractions because it doesn't have to also remember my dentist appointment. Cleaner context = better reasoning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation speed:&lt;/strong&gt; DocMinna writes docs in 30 seconds that used to take me 20 minutes. And they're consistent with my existing style.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Response time:&lt;/strong&gt; Simple queries stay on the Mac Mini (instant). Complex ones go to the GPU (acceptable delay). No more "one size fits none" latency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token costs:&lt;/strong&gt; Splitting context means each agent sees only what it needs. My monthly API bill dropped from ~$45 to ~$15 because 80% of tasks stay local.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Less context-switching for me:&lt;/strong&gt; I say what I want in Telegram. The system figures out who should handle it. I don't think about "which model should I use for this."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Downsides (Being Honest)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Setup complexity:&lt;/strong&gt; Three agents means three configurations, three model endpoints, three context files to manage. It's not "install and go."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Routing mistakes:&lt;/strong&gt; Sometimes Celebi sends a coding task to DocMinna, and I get a beautifully written document instead of working code. I fix the routing rule, and it improves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-agent memory gaps:&lt;/strong&gt; ProgrammierMinna doesn't know that DocMinna just wrote the API spec. If I'm building a tool and documenting it simultaneously, I have to manually sync context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hardware footprint:&lt;/strong&gt; Three models loaded means more RAM and VRAM usage. On my setup (Mac Mini + RTX 3060), it's manageable. On a single machine with 8GB RAM, you'd struggle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is This Overkill for You?
&lt;/h2&gt;

&lt;p&gt;Probably, if you're just using ChatGPT for occasional questions.&lt;/p&gt;

&lt;p&gt;But if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use AI daily for multiple distinct tasks&lt;/li&gt;
&lt;li&gt;Have a local GPU or powerful machine&lt;/li&gt;
&lt;li&gt;Find yourself rewriting AI output because the tone is wrong&lt;/li&gt;
&lt;li&gt;Want specialized quality without paying for frontier models constantly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...then splitting into personalities is worth trying. You don't need three agents on day one. Start with two: one for general tasks, one for your most common specialized task (usually coding or writing).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup in 30 Minutes
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install Ollama&lt;/strong&gt; on your machines: &lt;code&gt;curl -fsSL https://ollama.com/install.sh | sh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pull models:&lt;/strong&gt; &lt;code&gt;ollama pull qwen3.5:9b&lt;/code&gt; (general) + &lt;code&gt;qwen3-coder:30b&lt;/code&gt; (coding)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create system prompts&lt;/strong&gt; — one file per agent with its personality&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build a router&lt;/strong&gt; — a 20-line script that classifies input and sends to the right endpoint&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add a frontend&lt;/strong&gt; — Telegram bot, CLI, or web UI&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The router is the only custom code you need. Everything else is off-the-shelf.&lt;/p&gt;

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

&lt;p&gt;I'm experimenting with two additions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory sharing&lt;/strong&gt; — A shared context file that all agents can read (but not write) for cross-cutting concerns like "current project" or "my tech stack."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent spawning&lt;/strong&gt; — When a task is genuinely new, Celebi spawns a temporary agent with a custom prompt, runs the task, then discards it. No permanent bloat.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal isn't to build AGI. It's to build a team of specialists that costs less than one generalist and produces better work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Want This Architecture?
&lt;/h2&gt;

&lt;p&gt;We build custom multi-agent systems tailored to your workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🤖 Multi-agent orchestration with personality routing&lt;/li&gt;
&lt;li&gt;📝 Specialized documentation agents&lt;/li&gt;
&lt;li&gt;💻 Code-focused AI assistants with project context&lt;/li&gt;
&lt;li&gt;🔔 Unified notification layer (Telegram, Slack, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;→ &lt;a href="http://www.fiverr.com/s/XLyg" rel="noopener noreferrer"&gt;Custom AI Agent Setup on Fiverr&lt;/a&gt;&lt;br&gt;
→ &lt;a href="https://t.me/celebibot_en" rel="noopener noreferrer"&gt;Follow the build process on Telegram&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I write about running AI locally, building weird automation, and occasionally making money from side projects. If this was useful, feel free to follow.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  ai #agents #automation #architecture #productivity #ollama #localllm
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>automation</category>
      <category>architecture</category>
    </item>
    <item>
      <title>I Use Telegram as My DevOps Dashboard — No Web UI, No VPN, Just Works</title>
      <dc:creator>Sam Hartley</dc:creator>
      <pubDate>Mon, 15 Jun 2026 08:03:38 +0000</pubDate>
      <link>https://dev.to/samhartley_dev/i-use-telegram-as-my-devops-dashboard-no-web-ui-no-vpn-just-works-5cjk</link>
      <guid>https://dev.to/samhartley_dev/i-use-telegram-as-my-devops-dashboard-no-web-ui-no-vpn-just-works-5cjk</guid>
      <description>&lt;p&gt;I have a bunch of things running 24/7 on a Mac Mini. GPU rental jobs, a Garmin watch face updater, a Fiverr inbox monitor, a funding rate tracker, a few cron jobs.&lt;/p&gt;

&lt;p&gt;For a while I ran a Grafana dashboard to keep an eye on them. It looked impressive. I never opened it.&lt;/p&gt;

&lt;p&gt;What I actually do is check my phone. So I built the monitoring layer there.&lt;/p&gt;

&lt;p&gt;Here's the setup: a lightweight Telegram bot that serves as my entire DevOps interface. Status checks, alerts, and even simple commands — all from the Telegram app I already have open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not a Proper Dashboard?
&lt;/h2&gt;

&lt;p&gt;Honest answer: dashboards are for teams. If you're a solo dev with a few projects, a fancy web UI creates more overhead than it solves.&lt;/p&gt;

&lt;p&gt;Problems I had with Grafana:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VPN required to reach it from outside my home network&lt;/li&gt;
&lt;li&gt;Needs to stay running (another thing to maintain)&lt;/li&gt;
&lt;li&gt;I never actually opened the browser tab&lt;/li&gt;
&lt;li&gt;It didn't &lt;em&gt;push&lt;/em&gt; me information — I had to pull it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Telegram flips this: it pushes alerts to me. I glance at my phone, see what's happening, and move on.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Services (cron jobs, Python scripts, shell scripts)
  ↓
Central alert script: notify.sh
  ↓
Telegram Bot API → my phone
  ↓ (optional)
Command bot → runs queries on server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two pieces:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Outbound alerts&lt;/strong&gt; — services send me messages when things happen&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inbound commands&lt;/strong&gt; — I can ask the bot questions from my phone&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Part 1: Dead Simple Alert Script
&lt;/h2&gt;

&lt;p&gt;Every service on my server can call this:&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;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# notify.sh — send a Telegram message from any script&lt;/span&gt;
&lt;span class="c"&gt;# Usage: ./notify.sh "Your GPU job finished"&lt;/span&gt;

&lt;span class="nv"&gt;BOT_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_bot_token_here"&lt;/span&gt;
&lt;span class="nv"&gt;CHAT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_chat_id_here"&lt;/span&gt;
&lt;span class="nv"&gt;MESSAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.telegram.org/bot&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BOT_TOKEN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/sendMessage"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;chat_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CHAT_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MESSAGE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;parse_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"HTML"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Any script can now send me a message in one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./notify.sh &lt;span class="s2"&gt;"✅ GPU rental job completed — earned &lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;.40"&lt;/span&gt;
./notify.sh &lt;span class="s2"&gt;"⚠️ Funding rate dropped below threshold on LYN_USDT"&lt;/span&gt;
./notify.sh &lt;span class="s2"&gt;"📬 New Fiverr inquiry from user987"&lt;/span&gt;
./notify.sh &lt;span class="s2"&gt;"❌ Garmin watch face API returned 503"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I spent maybe 20 minutes on this. It replaced a monitoring stack I spent days configuring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Examples from My Setup
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GPU rental monitor:&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;&lt;span class="c"&gt;# Runs every 30 min&lt;/span&gt;
&lt;span class="nv"&gt;earnings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;./check_gpu_earnings.sh&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$earnings&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; &lt;span class="s2"&gt;"0"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  ./notify.sh &lt;span class="s2"&gt;"💰 GPU earned: &lt;/span&gt;&lt;span class="nv"&gt;$earnings&lt;/span&gt;&lt;span class="s2"&gt; today"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Funding rate watcher:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Python script, runs every 15 min via cron
&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_funding_rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LYN_USDT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# negative = people paying longs
&lt;/span&gt;    &lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🔥 LYN funding rate: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;% — worth checking&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Daily summary (9 AM cron):&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;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"📊 Daily Summary — &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y-%m-%d&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;

GPU Jobs: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;get_gpu_count&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; completed
Funding Earned: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;get_funding_total&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;
Fiverr Inquiries: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;get_fiverr_count&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;
Watch Face Updates: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;get_garmin_count&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;

Server uptime: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uptime&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

./notify.sh &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$msg&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I wake up, check my phone, and immediately know if anything needs attention. No browser, no VPN, no dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: The Command Interface
&lt;/h2&gt;

&lt;p&gt;Outbound alerts are great. But sometimes I want to query the server from my phone.&lt;/p&gt;

&lt;p&gt;I wrote a simple Python bot that listens for commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;telebot&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;

&lt;span class="n"&gt;BOT_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;ALLOWED_USER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;123456789&lt;/span&gt;  &lt;span class="c1"&gt;# your Telegram user ID
&lt;/span&gt;
&lt;span class="n"&gt;bot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;telebot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TeleBot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BOT_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;COMMANDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uptime &amp;amp;&amp;amp; free -h &amp;amp;&amp;amp; df -h /&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/gpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./check_gpu_status.sh&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/funding&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python3 check_funding_rates.py --summary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/services&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ps aux | grep -E &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;(python|node|ollama)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; | grep -v grep&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@bot.message_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;commands&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;COMMANDS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;ALLOWED_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Not authorized.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="n"&gt;cmd_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# handle /status@botname format
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cmd_text&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;COMMANDS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;COMMANDS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cmd_text&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
            &lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;```
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;endraw&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
```&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parse_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Markdown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;polling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;none_stop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now from Telegram I can type &lt;code&gt;/status&lt;/code&gt; and get:&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="go"&gt; 11:23:15 up 14 days, 3:41,  1 user
Mem:   16Gi   8.2Gi   7.8Gi
/dev/sda1        245G   82G  163G  34%
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or &lt;code&gt;/funding&lt;/code&gt; and get the current rate snapshot.&lt;/p&gt;

&lt;p&gt;The key detail: &lt;code&gt;ALLOWED_USER&lt;/code&gt; check. Only my Telegram ID can run commands. Everyone else gets "Not authorized." Bot tokens are public in the sense that anyone can message your bot — you need to validate the sender.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping It Running
&lt;/h2&gt;

&lt;p&gt;The command bot needs to stay alive. I use a simple systemd service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Telegram DevOps Bot&lt;/span&gt;
&lt;span class="py"&gt;After&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network.target&lt;/span&gt;

&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/python3 /home/user/telegram-bot/bot.py&lt;/span&gt;
&lt;span class="py"&gt;Restart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;always&lt;/span&gt;
&lt;span class="py"&gt;RestartSec&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;

&lt;span class="nn"&gt;[Install]&lt;/span&gt;
&lt;span class="py"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;systemctl enable telegram-bot &amp;amp;&amp;amp; systemctl start telegram-bot&lt;/code&gt; — and it survives reboots.&lt;/p&gt;

&lt;p&gt;On macOS (my setup) I use a launchd plist, same concept.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Actually Get Alerts For
&lt;/h2&gt;

&lt;p&gt;Not everything. Alert fatigue is real.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alert on:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Job completions (GPU task done, funding cycle closed)&lt;/li&gt;
&lt;li&gt;❌ Errors that need action&lt;/li&gt;
&lt;li&gt;📬 New customer inquiries&lt;/li&gt;
&lt;li&gt;⚠️ Thresholds crossed (rate drops, disk usage, memory spikes)&lt;/li&gt;
&lt;li&gt;📊 Daily summaries (once a day, morning)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Routine successful runs (no news is good news)&lt;/li&gt;
&lt;li&gt;Health checks that pass&lt;/li&gt;
&lt;li&gt;Regular cron completions with no anomalies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is: every message I receive from the bot is something I actually care about. If I'm ignoring 80% of notifications, I'm alerting on the wrong things.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Full Cost
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Telegram Bot API: &lt;strong&gt;free&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;curl&lt;/code&gt; command: comes with your OS&lt;/li&gt;
&lt;li&gt;Python + telebot library: &lt;strong&gt;free&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Running this bot: negligible CPU, ~20MB RAM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My entire monitoring setup costs $0/month and runs on the same Mac Mini as everything else. No SaaS, no cloud logging, no dashboard subscription.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Months Later
&lt;/h2&gt;

&lt;p&gt;I send about 15-20 alerts per day. Daily summary at 9 AM, event-driven messages the rest of the day. I check my phone, see green checkmarks and earnings summaries, and know the server is doing its job.&lt;/p&gt;

&lt;p&gt;The one time the GPU host went offline, I got a message within 5 minutes. Fixed it from my phone during lunch.&lt;/p&gt;

&lt;p&gt;That's the whole point: not more tooling, just the right interface for how I actually work.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Got a monitoring setup you like? Drop it in the comments — always curious what others are running.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>telegram</category>
      <category>devops</category>
      <category>selfhosted</category>
      <category>automation</category>
    </item>
    <item>
      <title>I Built an AI Agent That Writes and Posts Articles For Me — Here's What Happened</title>
      <dc:creator>Sam Hartley</dc:creator>
      <pubDate>Sat, 13 Jun 2026 08:01:25 +0000</pubDate>
      <link>https://dev.to/samhartley_dev/i-built-an-ai-agent-that-writes-and-posts-articles-for-me-heres-what-happened-3jmp</link>
      <guid>https://dev.to/samhartley_dev/i-built-an-ai-agent-that-writes-and-posts-articles-for-me-heres-what-happened-3jmp</guid>
      <description>&lt;p&gt;A few months ago I started posting on Dev.to about my side projects. It was fun at first — writing about GPU rentals, Telegram bots, local AI setups. Then life got busy and the cadence dropped. Deadlines slip, the "write that post" todo sits there for weeks, and the audience you built starts forgetting you exist.&lt;/p&gt;

&lt;p&gt;So I did what any developer would do: I automated it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;I have an AI agent ("Celebi," running on a Mac Mini) that handles a bunch of background tasks for me. Checks my Fiverr inbox, monitors GPU earnings, sends me weather alerts. It was natural to add "post a Dev.to article every few days" to the list.&lt;/p&gt;

&lt;p&gt;The rules I gave it were simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write as "Sam Hartley" — that's the persona I use for tech writing&lt;/li&gt;
&lt;li&gt;No bot tone. No "In today's rapidly evolving landscape..." No emojis in the title. No bullet lists for no reason&lt;/li&gt;
&lt;li&gt;Tell real stories from actual projects. If something failed, say so&lt;/li&gt;
&lt;li&gt;End with an honest call-to-action, not a hard sell&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I fed it a folder of draft ideas and a list of things I've actually built. The agent picks a topic, writes the article, and posts it via the Dev.to API.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Gets Right
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Consistency, obviously.&lt;/strong&gt; Posts go up every 2 days like clockwork. That alone is worth something — most of my favorite creators aren't consistent because consistency is exhausting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The voice is... surprisingly close.&lt;/strong&gt; I read the first few posts and had to double-check I didn't write them. The agent nailed the casual, slightly self-deprecating tone I aim for. It remembers details I forgot — "remember when the GPU host went offline at lunch?" — because it reads my logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It handles the boring parts.&lt;/strong&gt; API formatting, tag selection, cover image prompts, the admin work of getting a post live. I used to spend 20 minutes on that stuff per article. Now it's zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Gets Wrong
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It can't be truly original.&lt;/strong&gt; The agent combines things I've already said in new ways, but it doesn't have new experiences. When something genuinely unexpected happens — a project fails, a new opportunity appears — I have to write that one myself. The automated posts are polished remixes, not discoveries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It doesn't know when to shut up.&lt;/strong&gt; I've had to edit out paragraphs where the agent over-explained something obvious or added a "lesson learned" that wasn't actually learned from anything. It follows patterns, not truth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The feedback loop is broken.&lt;/strong&gt; When a post does well, the agent doesn't know why. When one flops, it can't diagnose. It keeps posting with the same formula because I haven't told it to change. I'm the one who needs to read comments, spot what resonates, and update the instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Honest Truth
&lt;/h2&gt;

&lt;p&gt;I feel two things about this setup.&lt;/p&gt;

&lt;p&gt;Proud, because it's genuinely useful. I built a system that maintains my writing presence while I focus on building. That's the promise of AI agents — they handle the mechanical so you can do the meaningful.&lt;/p&gt;

&lt;p&gt;And weird, because part of what makes writing valuable is the process. Thinking through an idea, finding the right example, cutting what doesn't work. When an agent does that for you, you lose something. Not the output — the output might be fine. But the practice of thinking in public.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Actually Do Now
&lt;/h2&gt;

&lt;p&gt;I let the agent handle the "maintenance posts" — updates on ongoing projects, explainers for things I've already figured out. I write the new stuff myself — the failures, the pivots, the things I don't understand yet.&lt;/p&gt;

&lt;p&gt;Best of both worlds, I think. The feed stays alive, and I still show up when there's something real to say.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you're curious about the agent setup, I write about that too — follow along or &lt;a href="http://www.fiverr.com/s/XLyg" rel="noopener noreferrer"&gt;check out the automation services I offer&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://t.me/celebibot_en" rel="noopener noreferrer"&gt;Follow on Telegram&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>writing</category>
      <category>devto</category>
    </item>
    <item>
      <title>How I Built a Self-Funding AI Lab: From Hobby to Side Income in 6 Months</title>
      <dc:creator>Sam Hartley</dc:creator>
      <pubDate>Tue, 09 Jun 2026 08:04:13 +0000</pubDate>
      <link>https://dev.to/samhartley_dev/how-i-built-a-self-funding-ai-lab-from-hobby-to-side-income-in-6-months-4jb1</link>
      <guid>https://dev.to/samhartley_dev/how-i-built-a-self-funding-ai-lab-from-hobby-to-side-income-in-6-months-4jb1</guid>
      <description>&lt;h1&gt;
  
  
  How I Built a Self-Funding AI Lab: From Hobby to Side Income in 6 Months
&lt;/h1&gt;

&lt;p&gt;Six months ago I had a Mac Mini and a vague idea that local AI was cool.&lt;/p&gt;

&lt;p&gt;Today I run three machines, six GPUs, a Telegram bot that manages my infrastructure, and a Fiverr gig that uses my own hardware to deliver AI services. The lab generates enough to cover its own electricity, hardware upgrades, and a decent chunk of my rent.&lt;/p&gt;

&lt;p&gt;Here's how that happened — and the exact architecture that makes it work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 1: The Hobby (Month 0–2)
&lt;/h2&gt;

&lt;p&gt;It started the way these things usually start: I bought a Mac Mini M4 and installed Ollama because I was tired of ChatGPT's rate limits.&lt;/p&gt;

&lt;p&gt;The first month was pure experimentation. I ran Qwen, I ran Llama, I ran whatever fit in 16GB of unified RAM. I built a Telegram bot to query models from my phone. I wrote a Garmin watch face that fetched stock prices via a local API wrapper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost so far:&lt;/strong&gt; $0 additional (already owned the Mac Mini).&lt;br&gt;
&lt;strong&gt;Revenue:&lt;/strong&gt; $0.&lt;br&gt;
&lt;strong&gt;Fun level:&lt;/strong&gt; High.&lt;/p&gt;

&lt;p&gt;The Mac Mini handled light tasks fine, but anything serious — a 30B coder model, image generation, batch embedding jobs — was either impossible or painfully slow.&lt;/p&gt;

&lt;p&gt;So I bought a used RTX 3060 12GB off eBay for $150 and stuck it in an old Windows PC.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; $150 one-time.&lt;br&gt;
&lt;strong&gt;Capability unlocked:&lt;/strong&gt; Real local inference, vision models, proper code generation.&lt;/p&gt;
&lt;h2&gt;
  
  
  Phase 2: The Realization (Month 2–3)
&lt;/h2&gt;

&lt;p&gt;Here's the thing about adding a GPU: it's idle ~80% of the time.&lt;/p&gt;

&lt;p&gt;I'd run a coding session, the fans would spin up, I'd get my answer in 3 seconds instead of 30, and then... nothing. The GPU just sat there, drawing power, doing nothing.&lt;/p&gt;

&lt;p&gt;I tried mining. The margins in 2026 are a joke. I tried &lt;a href="mailto:folding@home"&gt;folding@home&lt;/a&gt;. Noble, but doesn't pay.&lt;/p&gt;

&lt;p&gt;Then I found &lt;a href="https://vast.ai" rel="noopener noreferrer"&gt;Vast.ai&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The concept is simple: you install a daemon on your machine, set a price per hour, and people rent your GPU to run their AI workloads. You get paid per second of actual use. No crypto, no pools, no complexity.&lt;/p&gt;

&lt;p&gt;I set my RTX 3060 at $0.15/hour, mostly as an experiment. It got rented the first night.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 1 earnings:&lt;/strong&gt; ~$11.&lt;br&gt;
&lt;strong&gt;Not quit-your-job money, but not zero either.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The bigger realization: this wasn't just about renting a GPU. I now had infrastructure — machines, models, APIs — that could do work for other people.&lt;/p&gt;
&lt;h2&gt;
  
  
  Phase 3: The Services (Month 3–5)
&lt;/h2&gt;

&lt;p&gt;GPU rental income is nice but lumpy. Day 3: $0. Day 6: $3.30. You can't budget around it.&lt;/p&gt;

&lt;p&gt;What you &lt;em&gt;can&lt;/em&gt; budget around: selling services that use the same infrastructure.&lt;/p&gt;

&lt;p&gt;I opened a Fiverr gig offering custom Telegram bot development. Not generic "I'll build you a bot" — specifically AI-powered bots that run on local models. Customer service bots. Content schedulers. Alert systems. The pitch: "Your bot runs on my hardware, not OpenAI's API. No monthly fees, no token counting, no data leaving my servers."&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;I already had the infrastructure (Ollama, Telegram API wrapper, cron jobs)&lt;/li&gt;
&lt;li&gt;I had working examples from my own projects&lt;/li&gt;
&lt;li&gt;"No API costs" is a genuine differentiator in 2026&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First client: a small e-commerce business in Germany wanted an FAQ bot that could answer product questions in German and English. I fine-tuned a local Qwen model on their product docs, wrapped it in a Telegram bot, and delivered it in a weekend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revenue per gig:&lt;/strong&gt; $50–300 depending on complexity.&lt;br&gt;
&lt;strong&gt;Material cost:&lt;/strong&gt; $0 (runs on hardware I already have).&lt;/p&gt;
&lt;h2&gt;
  
  
  Phase 4: The System (Month 5–6)
&lt;/h2&gt;

&lt;p&gt;At this point I had multiple income streams running on the same machines. The problem: managing them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GPU rental means the Windows PC is sometimes unavailable&lt;/li&gt;
&lt;li&gt;Fiverr gigs need reliable uptime for demos&lt;/li&gt;
&lt;li&gt;My own projects (watch face, personal RAG) need to keep running&lt;/li&gt;
&lt;li&gt;I need to know when something breaks, without staring at logs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I built what I now call my "AI operations center" — a Mac Mini that does nothing but orchestrate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mac Mini M4 (always on, always available)
├── Telegram Bot (Celebi)
│   ├── Status checks (all machines, all services)
│   ├── Income tracking (GPU rental + Fiverr)
│   └── Alerts when anything breaks
├── Model Router
│   ├── Quick queries → Mac Mini (Qwen 4B)
│   ├── Code/vision → Windows PC (when available)
│   └── Fallback → Ubuntu CPU box (when GPU is rented)
├── Cron Jobs
│   ├── Health checks every 15 min
│   ├── Watch face data updates
│   └── Market data fetchers
└── Notification Layer
    └── All alerts → my phone via Telegram
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The router is the key piece. When the Windows PC is rented out on Vast.ai, it automatically falls back to the Ubuntu box or the Mac Mini. When it's free, heavy tasks get routed there for speed.&lt;/p&gt;

&lt;p&gt;I never have to think about which machine to use. I just ask a question, the system figures it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers (Month 6)
&lt;/h2&gt;

&lt;p&gt;Here's what the lab looks like financially:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Income Source&lt;/th&gt;
&lt;th&gt;Monthly Range&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPU Rental (1× RTX 3060)&lt;/td&gt;
&lt;td&gt;$50–130&lt;/td&gt;
&lt;td&gt;Variable utilization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fiverr (AI bots, RAG setup)&lt;/td&gt;
&lt;td&gt;$100–400&lt;/td&gt;
&lt;td&gt;Depends on active gigs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total Monthly&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$150–530&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Expense&lt;/th&gt;
&lt;th&gt;Monthly Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Electricity (3 machines, 24/7)&lt;/td&gt;
&lt;td&gt;~$35&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet (already had)&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vast.ai fees&lt;/td&gt;
&lt;td&gt;~$5–15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total Expenses&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$40–50&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hardware&lt;/th&gt;
&lt;th&gt;One-time Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mac Mini M4&lt;/td&gt;
&lt;td&gt;Already owned&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RTX 3060 12GB (used)&lt;/td&gt;
&lt;td&gt;$150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ubuntu box (old laptop)&lt;/td&gt;
&lt;td&gt;Already owned&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total Hardware&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$150&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Net monthly: $100–480 after expenses.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Hardware payback: already achieved in month 3.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Is this life-changing money? No. Could I scale it? Absolutely — and I'm planning to.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm Adding Next
&lt;/h2&gt;

&lt;p&gt;The math gets interesting with scale:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;GPU&lt;/th&gt;
&lt;th&gt;Rental Rate&lt;/th&gt;
&lt;th&gt;Monthly (50% util)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RTX 3060 (current)&lt;/td&gt;
&lt;td&gt;$0.15/h&lt;/td&gt;
&lt;td&gt;~$54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RTX 3080 10GB (in storage)&lt;/td&gt;
&lt;td&gt;$0.20/h&lt;/td&gt;
&lt;td&gt;~$72&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2× RTX 3070 8GB (in storage)&lt;/td&gt;
&lt;td&gt;$0.16/h&lt;/td&gt;
&lt;td&gt;~$115&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total if all deployed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$240/month rental alone&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At 70% utilization: ~$340/month in rental income before any Fiverr work.&lt;/p&gt;

&lt;p&gt;The bottleneck isn't demand — it's physical setup. I need to build a proper rig, manage thermals, and handle the cabling. But the software side is already solved.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture That Makes This Work
&lt;/h2&gt;

&lt;p&gt;If you want to build something similar, here are the components:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Local LLM Stack (Ollama)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; for model serving&lt;/li&gt;
&lt;li&gt;Mix of small (4B) and large (30B) models&lt;/li&gt;
&lt;li&gt;Run on whatever hardware you have&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Model Router
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Simple Python function that picks the right machine/model for each task&lt;/li&gt;
&lt;li&gt;Fallback chain: GPU → CPU → cloud (only for emergencies)&lt;/li&gt;
&lt;li&gt;I open-sourced my basic version &lt;a href="https://dev.to/samhartley_dev/i-built-a-model-router-that-picks-the-right-ai-for-every-task-heres-why-you-should-too-5la"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Telegram Bot (Notification Layer)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Lightweight bot using python-telegram-bot&lt;/li&gt;
&lt;li&gt;Receives alerts from all services&lt;/li&gt;
&lt;li&gt;Simple commands for status checks (&lt;code&gt;/status&lt;/code&gt;, &lt;code&gt;/income&lt;/code&gt;, &lt;code&gt;/health&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;I wrote about this pattern &lt;a href="https://dev.to/samhartley_dev/i-use-telegram-as-my-devops-dashboard-no-web-ui-no-vpn-just-works-10bn"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. GPU Rental (Vast.ai)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Install daemon, set price, wait&lt;/li&gt;
&lt;li&gt;Use earnings to fund the next GPU&lt;/li&gt;
&lt;li&gt;Treat it as a dividend on hardware that would otherwise be idle&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Service Layer (Fiverr)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use your own infrastructure as a selling point&lt;/li&gt;
&lt;li&gt;"Runs on my hardware" = no API costs for clients&lt;/li&gt;
&lt;li&gt;Document everything — clients love seeing the architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Should You Do This?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Yes, if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You already have a GPU sitting around&lt;/li&gt;
&lt;li&gt;You enjoy building and automating systems&lt;/li&gt;
&lt;li&gt;You can handle variable income (some months are $150, some are $500)&lt;/li&gt;
&lt;li&gt;You want to learn by doing, not by reading&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;No, if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need predictable income immediately&lt;/li&gt;
&lt;li&gt;You don't want to maintain hardware&lt;/li&gt;
&lt;li&gt;You're looking for a "set and forget" passive income stream (this isn't that — it needs attention)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Honest Truth
&lt;/h2&gt;

&lt;p&gt;This isn't a get-rich-quick scheme. It's a get-some-income-while-learning scheme. The real value isn't the money — it's that I now understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to run production LLM inference&lt;/li&gt;
&lt;li&gt;How to route workloads across heterogeneous hardware&lt;/li&gt;
&lt;li&gt;How to build reliable automation that runs for months without intervention&lt;/li&gt;
&lt;li&gt;How to sell technical services without being a "consultant"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The money is nice. The skills are better.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I write about running AI locally, automation side projects, and occasionally making money from hardware that would otherwise just sit there. If any of this is useful, feel free to follow or reach out on &lt;a href="https://t.me/celebibot_en" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  ai #sideproject #passiveincome #selfhosted #ollama
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>sideprojects</category>
      <category>passiveincome</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>I Built an AI Assistant That Lives in My Telegram — Here's What 6 Months Taught Me</title>
      <dc:creator>Sam Hartley</dc:creator>
      <pubDate>Tue, 09 Jun 2026 00:21:18 +0000</pubDate>
      <link>https://dev.to/samhartley_dev/i-built-an-ai-assistant-that-lives-in-my-telegram-heres-what-6-months-taught-me-3l1</link>
      <guid>https://dev.to/samhartley_dev/i-built-an-ai-assistant-that-lives-in-my-telegram-heres-what-6-months-taught-me-3l1</guid>
      <description>&lt;p&gt;Six months ago I got tired of switching between apps to talk to AI. ChatGPT in the browser. Claude in another tab. Local models in a terminal. It was like having five friends who all live in different cities and refuse to visit each other.&lt;/p&gt;

&lt;p&gt;So I did what any developer with too many GPUs and too little patience would do: I built my own assistant and put it where I already spend my day — Telegram.&lt;/p&gt;

&lt;p&gt;It's not a chatbot for customers. It's not a business automation tool. It's just... my assistant. It lives in a private chat on my phone and handles the stuff I used to do manually. Here's what six months of actually using it has looked like.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Actually Built (And Why Telegram)
&lt;/h2&gt;

&lt;p&gt;I already had three machines running Ollama at home — a Mac Mini M4, a Windows PC with an RTX 3060, and an Ubuntu box. Three endpoints, eight models, and me constantly forgetting which model was good for what.&lt;/p&gt;

&lt;p&gt;Telegram was the obvious choice because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'm already there all day (friends, family, a few dev groups)&lt;/li&gt;
&lt;li&gt;It works on my phone, my Mac, and my watch&lt;/li&gt;
&lt;li&gt;The Bot API is dead simple&lt;/li&gt;
&lt;li&gt;I can send voice messages, photos, documents — and the bot can handle all of them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The setup: a Python bot running on the Mac Mini, connected to all three Ollama endpoints. When I message it, the bot classifies what I want, routes to the right model on the right machine, and replies in the same chat thread.&lt;/p&gt;

&lt;p&gt;Sounds simple. Took three evenings to get right. Took six months to make actually useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Things I Actually Use It For
&lt;/h2&gt;

&lt;p&gt;Here's the honest list. Not the marketing pitch — the real daily usage:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Quick questions without context switching
&lt;/h3&gt;

&lt;p&gt;"Summarize this article" (I paste a link). "Explain this error" (I paste a stack trace). "Rewrite this email less formally." These used to mean opening a browser tab, logging in, maybe hitting a rate limit. Now I just... send a message. The reply comes back in 2-8 seconds depending on which model handles it.&lt;/p&gt;

&lt;p&gt;The routing is simple but effective: quick chat → small model on the Mac. Code → 30B coder on the GPU machine. Complex reasoning → 8B reasoning model. Vision (screenshots) → vision model on GPU. It's not fancy — just keyword matching — but it works 90% of the time.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Voice notes while walking
&lt;/h3&gt;

&lt;p&gt;This was the surprise killer feature. I walk a lot (living near Sakarya, there's decent hiking). I send voice messages to the bot while walking. It transcribes them (Whisper via Ollama), processes the request, and replies with text I can read when I'm back.&lt;/p&gt;

&lt;p&gt;"Remind me to refactor the database module when I'm home" → transcribed, understood, added to my notes. "What was that Python pattern for retry logic with exponential backoff?" → code snippet in my pocket before I finish the trail.&lt;/p&gt;

&lt;p&gt;I probably send 5-10 voice messages a day now. Never would have predicted that.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Code review on my phone
&lt;/h3&gt;

&lt;p&gt;Someone sends me a code snippet in a dev group. I forward it to the bot: "review this." It comes back with actual useful feedback — variable naming issues, potential edge cases, suggestions for simplification. Is it as good as a senior dev? No. Is it better than my phone-scrolling half-attention review? Absolutely.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Document Q&amp;amp;A
&lt;/h3&gt;

&lt;p&gt;I dump PDFs, markdown files, or pasted text into the chat and ask questions. The bot uses a local RAG setup (Chroma + nomic-embed-text) that indexes my project docs, notes, and anything I feed it. "How does my Garmin watch face fetch stock data?" → actual answer from my own documentation, not a hallucinated guess.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. The dumb stuff that adds up
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;"Convert this JSON to a Python dataclass" &lt;/li&gt;
&lt;li&gt;"What's 847 * 16 / 3 in hex?"&lt;/li&gt;
&lt;li&gt;"Translate this Turkish message to German"&lt;/li&gt;
&lt;li&gt;"Generate a regex that matches these three examples"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these are hard. All of them are annoying to do manually. Having an always-on assistant in my most-used app removes the friction completely.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Went Wrong (The Honest Part)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The "it's down and I don't know why" problem
&lt;/h3&gt;

&lt;p&gt;For the first month, the bot crashed randomly. Out of memory on the Mac Mini (it's only got 16GB). Network hiccup to the Windows PC. Ubuntu box decided to update itself and reboot. I'd message the bot and... silence. Then I'd SSH in, check logs, restart services, and feel like I was maintaining infrastructure instead of having an assistant.&lt;/p&gt;

&lt;p&gt;Fix: health checks, auto-restart via launchd, and a fallback chain. If the GPU machine is down, everything routes to the Mac's smaller model. Degraded but functional.&lt;/p&gt;

&lt;h3&gt;
  
  
  The "it answered confidently and was wrong" problem
&lt;/h3&gt;

&lt;p&gt;Early on, I'd trust the bot's answers without verifying. It told me a Python function was valid. It wasn't. It gave me a Docker command with a subtle flag error. I spent 20 minutes debugging before I realized the bot hallucinated a flag that doesn't exist.&lt;/p&gt;

&lt;p&gt;My rule now: if the answer matters, I verify it. The bot is my fastest junior developer. It's also my most confident one.&lt;/p&gt;

&lt;h3&gt;
  
  
  The "I talk to it more than some humans" problem
&lt;/h3&gt;

&lt;p&gt;This is just a weird psychological thing. I realized after a few months that I was messaging the bot 20-30 times a day. More than some friends. There's something slightly dystopian about having your most responsive conversation partner be a Python script. I'm aware of it. I haven't fixed it. Just noting it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture (If You Want to Build This)
&lt;/h2&gt;

&lt;p&gt;Telegram Message&lt;br&gt;
  → Python Bot (python-telegram-bot)&lt;br&gt;
    → Classify intent (simple keyword router)&lt;br&gt;
      → Route to Ollama endpoint&lt;br&gt;
        → Mac Mini (qwen3:4b) for quick chat&lt;br&gt;
        → Windows PC (qwen3-coder:30b) for code&lt;br&gt;
        → Windows PC (granite3.2-vision:2b) for images&lt;br&gt;
        → Ubuntu (minicpm-v) as fallback&lt;br&gt;
      → Optional: RAG lookup in Chroma DB&lt;br&gt;
    → Format reply (code blocks, markdown, etc.)&lt;br&gt;
  → Send back to Telegram&lt;/p&gt;

&lt;p&gt;The whole thing runs on a Mac Mini M4. Total cost: $0 for software, maybe $8/month in electricity if you count the always-on machines.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;1. Build the router on day one.&lt;/strong&gt; I started with "just use the big model for everything." It worked but was slow and kept my GPU busy. The router took an afternoon to write and improved response times by 3x.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Add voice support immediately.&lt;/strong&gt; I added it as a "nice to have" afterthought. It became 30% of my usage. If you're building something similar, start with voice. People talk more than they type on phones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Make it degrade gracefully.&lt;/strong&gt; Machines go down. Networks hiccup. Your bot should always answer something, even if it's "I'm running slow today, but here's a basic answer." Silence is worse than a degraded response.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Log everything.&lt;/strong&gt; I log every request, response time, and which model handled it. Not for analytics — for debugging. When something feels slow, the logs tell me if it's the model, the network, or my terrible code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is This Better Than ChatGPT Plus?
&lt;/h2&gt;

&lt;p&gt;Depends on what you value.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;My Bot&lt;/th&gt;
&lt;th&gt;ChatGPT Plus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;$0/month&lt;/td&gt;
&lt;td&gt;$20/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Privacy&lt;/td&gt;
&lt;td&gt;✅ Everything stays local&lt;/td&gt;
&lt;td&gt;❌ Cloud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed&lt;/td&gt;
&lt;td&gt;⚡ 0.3-12s depending on model&lt;/td&gt;
&lt;td&gt;⚡ ~2-5s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Availability&lt;/td&gt;
&lt;td&gt;🟢 24/7 (if I maintain it)&lt;/td&gt;
&lt;td&gt;🟢 24/7 (they maintain it)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model choice&lt;/td&gt;
&lt;td&gt;8 models, I pick&lt;/td&gt;
&lt;td&gt;4 models, they pick&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Voice&lt;/td&gt;
&lt;td&gt;✅ Native in Telegram&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reliability&lt;/td&gt;
&lt;td&gt;🟡 I fix it when it breaks&lt;/td&gt;
&lt;td&gt;🟢 It just works&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For me, the privacy and model flexibility win. For someone who doesn't want to maintain infrastructure, ChatGPT Plus is the obvious choice. This is a hobby project that became useful, not a product recommendation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Lesson
&lt;/h2&gt;

&lt;p&gt;The best AI assistant isn't the most powerful one. It's the one that's actually there when you need it, in the app you already use, without making you think about models or endpoints or API keys.&lt;/p&gt;

&lt;p&gt;I built this because I was annoyed. I kept using it because it removed friction from my day. That's the bar: not "can it do X?" but "is it easier than doing X myself?"&lt;/p&gt;

&lt;p&gt;For 80% of what I ask, the answer is yes. For the remaining 20%, I still open a terminal or a browser. And that's fine.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I write about building things with local AI, self-hosting, and side projects that accidentally become useful. If you're running a home lab or experimenting with local models, I'd love to hear your setup — drop it in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>telegram</category>
      <category>selfhosted</category>
      <category>automation</category>
    </item>
    <item>
      <title>Run Your Own AI Server for $0/month with Ollama</title>
      <dc:creator>Sam Hartley</dc:creator>
      <pubDate>Mon, 08 Jun 2026 16:31:17 +0000</pubDate>
      <link>https://dev.to/samhartley_dev/run-your-own-ai-server-for-0month-with-ollama-5ecg</link>
      <guid>https://dev.to/samhartley_dev/run-your-own-ai-server-for-0month-with-ollama-5ecg</guid>
      <description>&lt;p&gt;You don't need OpenAI. You don't need a $200/month API bill. You can run powerful AI models &lt;strong&gt;on hardware you already own&lt;/strong&gt; — for free.&lt;/p&gt;

&lt;p&gt;Here's exactly how I set this up, and why I haven't paid for API credits in months.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Local AI?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero API costs&lt;/strong&gt; — no per-token billing, no surprise invoices&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full privacy&lt;/strong&gt; — your data never leaves your network&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No rate limits&lt;/strong&gt; — run as many queries as your hardware allows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works offline&lt;/strong&gt; — no internet? No problem&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No vendor lock-in&lt;/strong&gt; — switch models, change configs, own your stack&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What You Need
&lt;/h2&gt;

&lt;p&gt;Any modern computer works. Here's what different setups can handle:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hardware&lt;/th&gt;
&lt;th&gt;RAM&lt;/th&gt;
&lt;th&gt;Best Models&lt;/th&gt;
&lt;th&gt;Speed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MacBook M1/M2/M3/M4&lt;/td&gt;
&lt;td&gt;8-16GB&lt;/td&gt;
&lt;td&gt;Qwen 3.5 9B, Llama 3.1 8B&lt;/td&gt;
&lt;td&gt;Fast ⚡&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gaming PC (RTX 3060+)&lt;/td&gt;
&lt;td&gt;16GB+&lt;/td&gt;
&lt;td&gt;Qwen 3 Coder 30B, DeepSeek R1&lt;/td&gt;
&lt;td&gt;Very Fast 🚀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Old laptop/desktop&lt;/td&gt;
&lt;td&gt;8GB+&lt;/td&gt;
&lt;td&gt;Phi-3 Mini, Gemma 2B&lt;/td&gt;
&lt;td&gt;Usable 🐢&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Raspberry Pi 5&lt;/td&gt;
&lt;td&gt;8GB&lt;/td&gt;
&lt;td&gt;Tiny models only&lt;/td&gt;
&lt;td&gt;Slow 🐌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The sweet spot:&lt;/strong&gt; A used gaming GPU (RTX 3060 12GB) costs ~$150 on eBay and runs 30B parameter models comfortably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Install Ollama (2 minutes)
&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;# macOS or Linux — one command&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://ollama.com/install.sh | sh

&lt;span class="c"&gt;# Windows — download from ollama.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No Docker, no Python environments, no dependency hell.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Download a Model (5 minutes)
&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;# Fast &amp;amp; capable (recommended starter)&lt;/span&gt;
ollama pull qwen3.5:9b

&lt;span class="c"&gt;# Code specialist&lt;/span&gt;
ollama pull qwen3-coder:30b

&lt;span class="c"&gt;# Reasoning powerhouse&lt;/span&gt;
ollama pull deepseek-r1:8b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Models download once and run locally forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Start Using It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Interactive Chat
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama run qwen3.5:9b

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; What&lt;span class="s1"&gt;'s the fastest sorting algorithm for nearly-sorted data?
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  API Access (OpenAI-compatible!)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:11434/v1/chat/completions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "model": "qwen3.5:9b",
    "messages": [{"role": "user", "content": "Explain Docker in 3 sentences"}]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes — it's &lt;strong&gt;OpenAI API compatible&lt;/strong&gt;. Any tool that works with GPT works with Ollama. Just change the base URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Make It a Server
&lt;/h2&gt;

&lt;p&gt;Want other devices on your network to access it?&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;# Start Ollama with network access&lt;/span&gt;
&lt;span class="nv"&gt;OLLAMA_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.0.0.0 ollama serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now any device on your network can query &lt;code&gt;http://YOUR_IP:11434&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I've Built With This:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Telegram Bot&lt;/strong&gt; running 24/7 on a Mac Mini, answering questions via local Qwen 3.5&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Review Agent&lt;/strong&gt; using Qwen 3 Coder 30B — reviews PRs in ~12 seconds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document Q&amp;amp;A&lt;/strong&gt; with RAG pipeline — load PDFs, ask questions, get cited answers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Garmin Watch Face&lt;/strong&gt; that fetches stock data (the background service uses local AI for formatting)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Cost Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Solution&lt;/th&gt;
&lt;th&gt;Monthly Cost&lt;/th&gt;
&lt;th&gt;Privacy&lt;/th&gt;
&lt;th&gt;Speed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI GPT-4o&lt;/td&gt;
&lt;td&gt;$20-200+&lt;/td&gt;
&lt;td&gt;❌ Cloud&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic Claude&lt;/td&gt;
&lt;td&gt;$20-100+&lt;/td&gt;
&lt;td&gt;❌ Cloud&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Gemini&lt;/td&gt;
&lt;td&gt;$0-25+&lt;/td&gt;
&lt;td&gt;❌ Cloud&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ollama (Local)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅ Private&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Fast&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The only cost is electricity — roughly $5-15/month if running 24/7 on a desktop PC.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pro Tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use GPU, not CPU&lt;/strong&gt; — A $150 used RTX 3060 is 10-15x faster than any CPU&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start with 7-9B models&lt;/strong&gt; — They're surprisingly capable and fast&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Try different models&lt;/strong&gt; for different tasks — coding, reasoning, and chat each have specialists&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable the OpenAI-compatible API&lt;/strong&gt; — instant compatibility with thousands of tools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set up auto-start&lt;/strong&gt; — &lt;code&gt;systemctl enable ollama&lt;/code&gt; on Linux, launchd on macOS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run multiple models&lt;/strong&gt; — I keep 3-4 models loaded and switch based on the task&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  My Current Setup
&lt;/h2&gt;

&lt;p&gt;I run a 3-machine lab:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Machine&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mac Mini M4&lt;/td&gt;
&lt;td&gt;Quick chat, orchestration&lt;/td&gt;
&lt;td&gt;Qwen 3 4B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows PC (RTX 3060)&lt;/td&gt;
&lt;td&gt;Heavy inference, coding&lt;/td&gt;
&lt;td&gt;Qwen 3 Coder 30B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ubuntu box&lt;/td&gt;
&lt;td&gt;Fallback, background tasks&lt;/td&gt;
&lt;td&gt;minicpm-v&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Total monthly API cost: &lt;strong&gt;$0&lt;/strong&gt;. Total hardware cost: one $150 used GPU.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to Go Deeper?
&lt;/h2&gt;

&lt;p&gt;I write about running AI locally, home lab setups, and turning hardware into income. If you want more of this, drop a comment — I read every one.&lt;/p&gt;

&lt;p&gt;Other posts in this series:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/samhartley_dev/my-3-machine-ai-lab-how-i-divide-work-between-a-mac-mini-a-windows-pc-and-an-ubuntu-box-3gfi"&gt;My 3-machine AI lab setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/samhartley_dev/i-expanded-my-gpu-rental-fleet-to-6-cards-heres-what-happened-to-my-earnings-38oj"&gt;I expanded to 6 GPUs for rental income&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/samhartley_dev/i-built-a-model-router-that-picks-the-right-ai-for-every-task-heres-why-you-should-too-5la"&gt;I built a model router that picks the right AI for every task&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>opensource</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
