<?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: Hugo Kuznicki</title>
    <description>The latest articles on DEV Community by Hugo Kuznicki (@hugo_kuznicki_1ff20709904).</description>
    <link>https://dev.to/hugo_kuznicki_1ff20709904</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%2F4006064%2Fd2d4b695-b32c-4fe1-921d-4a92a08977e4.jpg</url>
      <title>DEV Community: Hugo Kuznicki</title>
      <link>https://dev.to/hugo_kuznicki_1ff20709904</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hugo_kuznicki_1ff20709904"/>
    <language>en</language>
    <item>
      <title>Risk Rules Enforced in Code, Not Vibes: Building a Trading Engine With a Kill Switch</title>
      <dc:creator>Hugo Kuznicki</dc:creator>
      <pubDate>Mon, 13 Jul 2026 16:00:08 +0000</pubDate>
      <link>https://dev.to/hugo_kuznicki_1ff20709904/risk-rules-enforced-in-code-not-vibes-building-a-trading-engine-with-a-kill-switch-59pn</link>
      <guid>https://dev.to/hugo_kuznicki_1ff20709904/risk-rules-enforced-in-code-not-vibes-building-a-trading-engine-with-a-kill-switch-59pn</guid>
      <description>&lt;p&gt;Most trading automation fails in the same place: the risk rules live in the trader's head, not in the code. "I'll cut it if it moves against me." "I won't hold more than a few positions." Under pressure, those intentions bend. So I built a trading engine where the risk rules are enforced by the software and there's no polite way around them.&lt;/p&gt;

&lt;p&gt;It's called Apex Wallet. Here's the design idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rules are code, not suggestions
&lt;/h2&gt;

&lt;p&gt;Every incoming signal is checked against hard limits before anything executes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Max positions&lt;/strong&gt; — the engine refuses to open beyond the cap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portfolio-heat cap&lt;/strong&gt; — total risk exposure is bounded; a trade that would breach it is rejected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instant kill switch&lt;/strong&gt; — one action halts execution entirely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The point is that these aren't dashboards you're supposed to watch. They're gates in the execution path. A trade that violates a limit doesn't get a warning — it doesn't happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pluggable brokers: paper-to-live is a config change
&lt;/h2&gt;

&lt;p&gt;Execution goes through a broker abstraction with interchangeable backends — yfinance, ccxt, Alpaca. Paper trading and live trading are the same code path with a different adapter, so moving from simulation to real money is a configuration change, not a rewrite. That matters because the risk logic you tested in paper is &lt;em&gt;literally the same logic&lt;/em&gt; running live.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auditability by default
&lt;/h2&gt;

&lt;p&gt;Every decision is journaled. When something surprising happens, you can reconstruct exactly what the engine saw and why it acted — which signal came in, which checks passed, what executed. A trading system you can't audit is a trading system you can't trust.&lt;/p&gt;

&lt;p&gt;There's also a CLI and a local browser dashboard showing live positions and portfolio heat, so the state of the system is always visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture lesson (beyond trading)
&lt;/h2&gt;

&lt;p&gt;This pattern generalizes past finance: &lt;strong&gt;when a constraint really matters, encode it as a gate in the execution path, not as a guideline in a runbook.&lt;/strong&gt; Separate the thing that decides (signals) from the thing that enforces (risk checks) from the thing that acts (brokers). Each is testable in isolation, and the enforcement layer can't be skipped because it sits between decision and action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Automation you can trust comes from making the important rules unbreakable in code, keeping the risky boundary (paper vs. live) a config flag over identical logic, and journaling everything so it's auditable. That's the pattern — the trading part is just the example.&lt;/p&gt;

&lt;p&gt;If you want me to go deeper on the portfolio-heat calculation or the broker abstraction, let me know in the comments.&lt;/p&gt;

</description>
      <category>python</category>
      <category>automation</category>
      <category>architecture</category>
      <category>finance</category>
    </item>
    <item>
      <title>Ranking 80 Tickers in ~1 Second With Only Free Data</title>
      <dc:creator>Hugo Kuznicki</dc:creator>
      <pubDate>Sun, 12 Jul 2026 16:00:05 +0000</pubDate>
      <link>https://dev.to/hugo_kuznicki_1ff20709904/ranking-80-tickers-in-1-second-with-only-free-data-4l48</link>
      <guid>https://dev.to/hugo_kuznicki_1ff20709904/ranking-80-tickers-in-1-second-with-only-free-data-4l48</guid>
      <description>&lt;p&gt;Finding the handful of names worth looking at on any given day usually means one of two things: paying for a screener subscription, or clicking through dozens of charts by hand. I didn't want either, so I built a local scanner that does it automatically — and it runs on free data with nothing to subscribe to.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea
&lt;/h2&gt;

&lt;p&gt;Pull price and volume history for an 80-ticker universe, run each name through the technical signals that actually matter, and roll them into a single ranked list so the interesting setups float to the top.&lt;/p&gt;

&lt;h2&gt;
  
  
  The signals
&lt;/h2&gt;

&lt;p&gt;Each ticker gets evaluated for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Momentum&lt;/strong&gt; and recent trend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Volume spikes&lt;/strong&gt; vs. its own average&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Golden / death crosses&lt;/strong&gt; (moving-average crossovers)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RSI&lt;/strong&gt; conditions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Proximity to 52-week high / low&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Breakout&lt;/strong&gt; setups&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of reading six indicators per name, each rolls up into one &lt;strong&gt;composite score&lt;/strong&gt;. You get a ranked shortlist, not a spreadsheet you have to interpret.&lt;/p&gt;

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

&lt;p&gt;Python, Flask, and &lt;a href="https://github.com/ranaroussi/yfinance" rel="noopener noreferrer"&gt;yfinance&lt;/a&gt; for free OHLCV data — no paid feed. A signal-processing layer computes the indicators and combines them into the composite ranking. The front end is a sortable dashboard: every column sorts, inline sparklines show recent price action, filters narrow by signal type, and auto-refresh keeps the board current. Click any ticker for a detail chart.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I care about: speed
&lt;/h2&gt;

&lt;p&gt;It processes roughly &lt;strong&gt;54 tickers in about one second&lt;/strong&gt;. That number matters more than it looks. A scanner you have to wait on is a scanner you stop opening. When the broad universe collapses into a ranked shortlist almost instantly, checking the market becomes a glance instead of a chore.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes it reusable
&lt;/h2&gt;

&lt;p&gt;The signal logic is modular. The universe, the indicators, and the weighting are all things you can change — so &lt;em&gt;your&lt;/em&gt; edge (whatever thresholds and signals you actually trust) becomes the thing the scanner optimizes for. It replaces a paid screener and a lot of manual chart-flipping with one local dashboard at zero ongoing cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;You don't need a paid screener to turn a watchlist into a ranked shortlist. Free data plus a modular signal layer plus a fast dashboard gets you most of the way — and because it's local, there's nothing rate-limiting you out.&lt;/p&gt;

&lt;p&gt;If you'd want a breakdown of how the composite score is weighted, drop a comment — that's the piece people usually want to tune first.&lt;/p&gt;

</description>
      <category>python</category>
      <category>flask</category>
      <category>datascience</category>
      <category>finance</category>
    </item>
    <item>
      <title>I Built a $0 Local AI Automation Stack: Agentic Coding + Market Data Over MCP</title>
      <dc:creator>Hugo Kuznicki</dc:creator>
      <pubDate>Sat, 11 Jul 2026 23:00:45 +0000</pubDate>
      <link>https://dev.to/hugo_kuznicki_1ff20709904/i-built-a-0-local-ai-automation-stack-agentic-coding-market-data-over-mcp-1d92</link>
      <guid>https://dev.to/hugo_kuznicki_1ff20709904/i-built-a-0-local-ai-automation-stack-agentic-coding-market-data-over-mcp-1d92</guid>
      <description>&lt;p&gt;Serious AI-assisted development has a habit of turning into a stack of subscriptions: a coding-assistant plan, a market-data API, a backtesting service, model credits. Each one is reasonable on its own, and together they quietly become a monthly bill that also locks you into someone else's rate limits.&lt;/p&gt;

&lt;p&gt;I wanted to know how far you can get without any of that. The answer turned out to be: surprisingly far. Here's the stack I ended up with, running at $0 recurring cost and scripted so it rebuilds from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The goal
&lt;/h2&gt;

&lt;p&gt;A capable, &lt;em&gt;agentic&lt;/em&gt; AI workflow — coding &lt;strong&gt;and&lt;/strong&gt; quantitative research — running entirely on free and local infrastructure, and reproducible so it isn't a one-off config living on a single machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I wired together
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Agentic coding&lt;/strong&gt; runs through &lt;a href="https://aider.chat" rel="noopener noreferrer"&gt;Aider&lt;/a&gt;, configured to talk to local &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; models by default and fall back to the free tiers on Groq and OpenRouter when a task wants more horsepower. Same agent, same workflow, whether it's fully offline or tapping a free hosted model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Market data and research&lt;/strong&gt; run on &lt;a href="https://openbb.co" rel="noopener noreferrer"&gt;OpenBB&lt;/a&gt;, with &lt;strong&gt;MCP servers&lt;/strong&gt; set up so the AI agent can drive market-data queries directly. This is the part that changed how it feels to work: the agent doesn't just &lt;em&gt;suggest&lt;/em&gt; code that would fetch data — it calls a structured tool and pulls the actual data. &lt;strong&gt;VectorBT&lt;/strong&gt; handles fast, vectorized backtesting inside the same environment.&lt;/p&gt;

&lt;p&gt;The whole thing is documented and scripted, so it rebuilds rather than rots.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why MCP is the unlock
&lt;/h2&gt;

&lt;p&gt;The difference between "AI that writes code about your data" and "AI that operates on your data" is a tool interface. MCP (the Model Context Protocol) gives agents a structured way to call real tools — market data, internal APIs, a database — instead of hallucinating what the response might look like. Once the OpenBB layer was exposed over MCP, the agent could answer research questions by actually running the query.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tradeoffs (honest version)
&lt;/h2&gt;

&lt;p&gt;Local models aren't frontier models. For heavy reasoning I still route to a free hosted tier, and there are days the free tiers are rate-limited. The win isn't "local is as good as GPT-class" — it's that &lt;strong&gt;local-first with free-tier fallback covers the large majority of real work at zero marginal cost&lt;/strong&gt;, and keeps your code and data on your machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;If you want agentic tooling without committing to a stack of subscriptions — or you want agents that can &lt;em&gt;operate&lt;/em&gt; tools rather than just generate text — local-first routing plus MCP is a genuinely practical pattern in 2026. You get modern capability with the cost and privacy under your control.&lt;/p&gt;

&lt;p&gt;I'm writing up each piece of this stack in more detail. If there's a part you want to see first — the Aider/Ollama routing, the OpenBB MCP server, or the VectorBT backtests — say so in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>python</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How I Run My Content Tooling on a Local Model for $0</title>
      <dc:creator>Hugo Kuznicki</dc:creator>
      <pubDate>Sun, 28 Jun 2026 04:58:53 +0000</pubDate>
      <link>https://dev.to/hugo_kuznicki_1ff20709904/how-i-run-my-content-tooling-on-a-local-model-for-0-1oig</link>
      <guid>https://dev.to/hugo_kuznicki_1ff20709904/how-i-run-my-content-tooling-on-a-local-model-for-0-1oig</guid>
      <description>&lt;p&gt;A few months ago I added up what I was spending on AI APIs just to draft social posts. It wasn't a lot — a few dollars here, a few there — but it was a &lt;em&gt;recurring&lt;/em&gt; cost for something I do every single day. And every time I wanted to experiment, regenerate, or tweak a prompt, a little meter ticked in the back of my head telling me to stop wasting tokens.&lt;/p&gt;

&lt;p&gt;So I moved the whole thing local. No API keys, no per-token billing, nothing leaving my machine. Here's exactly how, including the parts that aren't as clean as the pitch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why local at all?
&lt;/h2&gt;

&lt;p&gt;Three reasons, in order of how much they actually mattered to me:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cost goes to zero.&lt;/strong&gt; Not "cheaper" — &lt;em&gt;zero&lt;/em&gt;. Once the model is on your disk, generating a thousand drafts costs the same as generating one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iteration becomes free, which changes your behavior.&lt;/strong&gt; This is the part nobody tells you. When each generation is metered, you ration attempts. When it's free, you regenerate aggressively — and the output gets &lt;em&gt;better&lt;/em&gt; because you stop being precious about it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy by default.&lt;/strong&gt; My prompts, drafts, and half-baked ideas never touch a third-party server. For content I haven't published yet, that's a real comfort.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The setup: Ollama in five minutes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; is the easiest way to run an LLM locally. Install it, pull a model, and you've got an HTTP server on &lt;code&gt;localhost&lt;/code&gt; that speaks a simple API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install (macOS/Linux)&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://ollama.com/install.sh | sh

&lt;span class="c"&gt;# Pull an instruct-tuned model&lt;/span&gt;
ollama pull llama3.1:8b

&lt;span class="c"&gt;# It's now serving on http://localhost:11434&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the entire infrastructure. No account, no key, no dashboard. The model runs as a local service and you talk to it over HTTP like any other API — except this one is on your machine and free.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pipeline
&lt;/h2&gt;

&lt;p&gt;My content workflow is deliberately boring: &lt;strong&gt;one topic in, a batch of platform-specific posts out.&lt;/strong&gt; The whole thing is a thin layer around three ideas — a per-platform prompt template, a call to the local model, and a tiny bit of cleanup.&lt;/p&gt;

&lt;p&gt;Here's the core call. Ollama exposes a &lt;code&gt;/api/generate&lt;/code&gt; endpoint:&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;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate&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="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;llama3.1:8b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;resp&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;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:11434/api/generate&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;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&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;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No SDK, no auth header, no &lt;code&gt;OPENAI_API_KEY&lt;/code&gt; in your environment. It's just a POST to localhost.&lt;/p&gt;

&lt;p&gt;The interesting part is the templating. Each platform gets its own prompt with its own constraints baked in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;TEMPLATES&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;twitter&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Write 3 punchy tweet hooks about: {topic}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Rules: under 280 chars, no hashtags, no emoji spam, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lead with the most surprising angle.&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;linkedin&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Write a short LinkedIn post about: {topic}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Rules: 1 strong opening line, 3 short paragraphs, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a question at the end. Plain language, no buzzwords.&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;thread&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Outline a 5-tweet thread about: {topic}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Each tweet on its own line, numbered, each able to stand alone.&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;def&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;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;platforms&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;out&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;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;platforms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TEMPLATES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Call &lt;code&gt;run("local LLMs for content", ["twitter", "linkedin", "thread"])&lt;/code&gt; and you get a dict of drafts back, generated entirely on your own hardware, for nothing.&lt;/p&gt;

&lt;p&gt;The real product wraps this with a UI, a platform picker, and output cleanup — but the engine is genuinely this small. That's the point. Most of the value isn't in the model; it's in the &lt;em&gt;templates&lt;/em&gt; that constrain the model into something usable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing that actually makes it good: tight prompts
&lt;/h2&gt;

&lt;p&gt;Smaller local models are less forgiving than a frontier API. A vague prompt to GPT-class hosted models still produces something passable. A vague prompt to an 8B local model produces mush. So the work shifts from "pay for a smarter model" to "write a sharper prompt."&lt;/p&gt;

&lt;p&gt;Concretely, what moved quality the most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bake the constraints into the template, not the topic.&lt;/strong&gt; Character limits, tone, structure — put them in the reusable template so every generation inherits them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask for multiple options.&lt;/strong&gt; "Write 3 hooks" beats "write a hook" — you pick the best and the model explores more of the space.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep a &lt;code&gt;Modelfile&lt;/code&gt; for a custom system prompt&lt;/strong&gt; if you find yourself repeating instructions:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; llama3.1:8b&lt;/span&gt;
SYSTEM "You are a concise copywriter. No clichés, no 'in today's
fast-paced world', no emoji unless asked. Plain, specific language."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama create copywriter &lt;span class="nt"&gt;-f&lt;/span&gt; Modelfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;code&gt;copywriter&lt;/code&gt; carries that voice everywhere and your per-call prompts get shorter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest tradeoffs
&lt;/h2&gt;

&lt;p&gt;I'm not going to pretend local is strictly better. It isn't.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Long-form coherence is weaker.&lt;/strong&gt; For short-form (hooks, captions, threads) local models are great. For a 2,000-word essay that needs to hold an argument, a frontier API still wins. Know which job you're doing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cold-start latency is real.&lt;/strong&gt; The first request after the model unloads is slow. Keep it warm if you generate in bursts (&lt;code&gt;ollama run&lt;/code&gt; in the background, or a keepalive ping).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You own the ops.&lt;/strong&gt; No hosted API means no one else patches, scales, or babysits it. For a personal tool that's fine; for a product serving others it's a real consideration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardware matters.&lt;/strong&gt; An 8B model is comfortable on a modern laptop. Bigger models want more RAM/VRAM. Match the model to your machine instead of reaching for the biggest one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trade I'm making — slightly less polish in exchange for $0 cost, full privacy, and unlimited iteration — is overwhelmingly worth it for high-frequency, templated work. That's most of what content generation actually is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The headline isn't "local models are magic." It's that &lt;strong&gt;for the specific job of churning out daily, templated content, the economics and the workflow both flip in local's favor&lt;/strong&gt; — and the setup is genuinely a five-minute Ollama install plus a few prompt templates.&lt;/p&gt;

&lt;p&gt;I packaged my own version of this into a small tool called &lt;strong&gt;Content Studio&lt;/strong&gt; (idea → batch of posts, runs fully local, $0 to run) if you'd rather not wire it up yourself — it's &lt;a href="https://kuznicki6.gumroad.com/l/kqusjo" rel="noopener noreferrer"&gt;on Gumroad&lt;/a&gt; and the open-source pieces live on &lt;a href="https://github.com/kuznickicapital-ship-it" rel="noopener noreferrer"&gt;my GitHub&lt;/a&gt;. And if you want the longer build-in-public breakdowns, I write them up in &lt;a href="https://hugos-newsletter-e0c067.beehiiv.com/" rel="noopener noreferrer"&gt;my newsletter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But honestly — even if you build your own from the snippets above, do it. Watching your API bill hit $0 while your output goes &lt;em&gt;up&lt;/em&gt; is a weirdly satisfying way to start a week.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>ollama</category>
      <category>localllm</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
