<?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: Warisha Danin Bilal</title>
    <description>The latest articles on DEV Community by Warisha Danin Bilal (@warishabilal7).</description>
    <link>https://dev.to/warishabilal7</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%2F4171114%2F9ea2a934-6cb6-4a92-b468-46c3e903729a.jpg</url>
      <title>DEV Community: Warisha Danin Bilal</title>
      <link>https://dev.to/warishabilal7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/warishabilal7"/>
    <language>en</language>
    <item>
      <title>magpie (Content Desk): How I Built an Offline AI Work Journal to Manage My Side Hustles, Societies, &amp; Applications</title>
      <dc:creator>Warisha Danin Bilal</dc:creator>
      <pubDate>Sun, 18 Oct 2026 21:09:22 +0000</pubDate>
      <link>https://dev.to/warishabilal7/magpie-content-desk-how-i-built-an-offline-ai-work-journal-to-manage-my-side-hustles-societies-16kg</link>
      <guid>https://dev.to/warishabilal7/magpie-content-desk-how-i-built-an-offline-ai-work-journal-to-manage-my-side-hustles-societies-16kg</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;As a student developer balancing coursework, side projects, job applications, and leadership roles in university societies, my biggest bottleneck was chaos. My technical progress lived in scattered git commits, draft ideas were lost in private Gemini/Claude chats, I constantly lost track of job application deadlines, and sitting down to write updates for Substack or LinkedIn felt like starting from a blank void every single time.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;magpie (&lt;code&gt;cdesk&lt;/code&gt;)&lt;/strong&gt; — an offline, local-first work journal, posting desk, and productivity hub.&lt;/p&gt;

&lt;p&gt;Instead of an AI that generates generic marketing fluff, magpie starts with the work you actually did:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Frictionless Capture Inbox:&lt;/strong&gt; One-command ingestion of daily git commits, raw notes, or exported AI chat histories (Gemini / Claude JSON), tagged by origin and deduplicated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source-Linked Work Journal:&lt;/strong&gt; Daily and weekly summaries where &lt;strong&gt;every single line cites the exact capture receipts&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Channel Workspaces:&lt;/strong&gt; Tailored drafting for Substack, LinkedIn, and university society channels. Each workspace has its own voice profile (via vector embeddings), platform formatting rules, and banned-phrase filters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic Fact-Checking &amp;amp; Receipt Checking:&lt;/strong&gt; The local model drafts, but pure Python deterministically audits the text. If the model hallucinates numbers, handles, links, or dates not grounded in your source captures, it catches them and retries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content Planner &amp;amp; Nudges:&lt;/strong&gt; Visual calendar views, &lt;code&gt;.ics&lt;/code&gt; Google Calendar export, and gentle "you haven't posted in $N$ days" cadence nudges.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Job Tracker &amp;amp; Resume Tailor:&lt;/strong&gt; A Kanban tracker for internships and jobs, paired with a pipeline that tailors resume bullets and cover letters backed strictly by citations from your real work journal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context Pack Generator:&lt;/strong&gt; Instantly compiles recent journal lines, decisions, and open questions into a single markdown brief to paste into any new AI session.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Who would pay for this?&lt;/strong&gt; Freelancers, solopreneurs, student builders, and developer advocates managing multiple side projects who want to maintain an active public presence and organized career pipeline without spending hours manually collating notes or paying hefty monthly SaaS subscriptions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Here is a full walkthrough of magpie in action — from ingesting git logs and chat exports to generating verified, cited drafts and managing the job application pipeline:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/pPropdBMF_0" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(You can also run the full Streamlit interface locally in one command: &lt;code&gt;streamlit run src/cdesk/app/Home.py&lt;/code&gt; or use the CLI via &lt;code&gt;cdesk&lt;/code&gt;)&lt;/em&gt;&lt;/p&gt;




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

&lt;p&gt;magpie is 100% open-source and local-first:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Warisha-Bilal7" rel="noopener noreferrer"&gt;
        Warisha-Bilal7
      &lt;/a&gt; / &lt;a href="https://github.com/Warisha-Bilal7/magpie" rel="noopener noreferrer"&gt;
        magpie
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;magpie was engineered with a strict principle: &lt;strong&gt;The model writes; deterministic code verifies, schedules, and counts.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Open-Source AI &amp;amp; Local Inference
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local LLMs via Ollama:&lt;/strong&gt; Runs completely offline with open-weight models (such as &lt;code&gt;qwen2.5:3b&lt;/code&gt;, &lt;code&gt;llama3.2&lt;/code&gt;, or &lt;code&gt;mistral&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local Embeddings:&lt;/strong&gt; Embeddings are generated locally and stored as binary BLOBs directly in SQLite for cosine-similarity voice matching and near-duplicate idea detection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline Template Fallback:&lt;/strong&gt; Every LLM node has a deterministic Jinja2 template fallback, meaning the entire system remains functional even on a low-spec laptop with Ollama turned off.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Stateful Graph Pipelines with LangGraph
&lt;/h3&gt;

&lt;p&gt;magpie splits work into three distinct LangGraph cycles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Journal Graph:&lt;/strong&gt; &lt;code&gt;select -&amp;gt; summarize (LLM) -&amp;gt; verify (receipt check) -&amp;gt; store&lt;/code&gt;. Unsupported claims are kicked back with exact violation feedback (up to 2 retries) before falling back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drafting Graph:&lt;/strong&gt; &lt;code&gt;gather -&amp;gt; voice matching -&amp;gt; write (LLM) -&amp;gt; fact_check -&amp;gt; rules_check -&amp;gt; save&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Job Tailor Graph:&lt;/strong&gt; &lt;code&gt;parse_jd (LLM) -&amp;gt; match_evidence -&amp;gt; write_bullets (LLM) -&amp;gt; verify (citations) -&amp;gt; store&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Architecture &amp;amp; Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; SQLite with SQLite FTS5 (full-text search) synchronized via SQLite triggers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; Streamlit multi-page app with clean kanban boards, markdown editors, and visual diff badges for rules violations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLI:&lt;/strong&gt; Python Typer + Rich (&lt;code&gt;cdesk capture&lt;/code&gt;, &lt;code&gt;cdesk journal&lt;/code&gt;, &lt;code&gt;cdesk draft&lt;/code&gt;, &lt;code&gt;cdesk tailor&lt;/code&gt;, &lt;code&gt;cdesk ics&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Open-source and local-first AI are essential for personal productivity tools:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Absolute Privacy for Sensitive Data:&lt;/strong&gt; A work journal contains unreleased code commits, internal team notes, personal thoughts, and job hunt statuses. Sending this raw telemetry to proprietary cloud APIs is a non-starter. Open innovation allows everything to run 100% on localhost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessible on Student Hardware:&lt;/strong&gt; Proprietary frontier models demand ongoing credit card subscriptions and API fees. By leveraging 4-bit quantized open-weight models (1B–7B parameters), Content Desk runs efficiently on an everyday student laptop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auditability &amp;amp; Determinism:&lt;/strong&gt; Open frameworks allow us to insert rigid verifiers between reasoning steps, eliminating hallucinations and ensuring the assistant remains grounded in real facts rather than speculative marketing fluff.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  My First User
&lt;/h2&gt;

&lt;p&gt;I built magpie out of personal necessity, and I was my own first user.&lt;/p&gt;

&lt;p&gt;Before this, I had three persistent friction points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deadlines slipping away:&lt;/strong&gt; Missing application deadlines and forgetting where I had applied or who I needed to follow up with.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;University Society updates:&lt;/strong&gt; Spending hours every weekend trying to remember what our student team shipped during the week to write announcement posts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content creation paralysis:&lt;/strong&gt; Knowing I needed to share technical learnings on Substack and LinkedIn, but getting stuck on the blank page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dogfooding magpie during its development changed my workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running &lt;code&gt;cdesk capture --git &amp;lt;repo-path&amp;gt;&lt;/code&gt; pulls my commits into the journal automatically at the end of the day.&lt;/li&gt;
&lt;li&gt;When drafting our society newsletter, the drafting graph produces a structured draft in our tone within seconds, complete with citations to the actual pull requests.&lt;/li&gt;
&lt;li&gt;The Kanban job tracker with deadline reminders has kept my application pipeline organized without context switching between three different note-taking apps.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What's Next for Content Desk
&lt;/h2&gt;

&lt;p&gt;This is just the beginning of my side hustle desk. On my roadmap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;👾 &lt;strong&gt;Desktop Application &amp;amp; Floating Widget:&lt;/strong&gt; Packaging Content Desk as a lightweight desktop widget so I can quick-capture thoughts or check due nudges with a global hotkey.&lt;/li&gt;
&lt;li&gt;🎨 &lt;strong&gt;Vintage Y2K Aesthetic:&lt;/strong&gt; Giving the UI a cohesive, playful retro Y2K theme with custom CSS styling to make daily planning and writing genuinely fun.&lt;/li&gt;
&lt;li&gt;🤖 &lt;strong&gt;Grokbot-Style Proactive Assistant:&lt;/strong&gt; Introducing an interactive, conversational buddy that actively nudges me about stalled job applications, brainstorms angles for society campaigns, and chats through project blockers.&lt;/li&gt;
&lt;li&gt;🧪 &lt;strong&gt;Further Polish &amp;amp; Edge-Case Debugging:&lt;/strong&gt; Continuing to refine citation regex heuristics and parser support for more chat export formats.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hacktoberfest Open-Source AI Challenge: Week 2 — Side Hustle&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>A golden hour walk planner that runs on a 1B model.</title>
      <dc:creator>Warisha Danin Bilal</dc:creator>
      <pubDate>Sun, 11 Oct 2026 21:50:58 +0000</pubDate>
      <link>https://dev.to/warishabilal7/a-golden-hour-walk-planner-that-runs-on-a-1b-model-kfp</link>
      <guid>https://dev.to/warishabilal7/a-golden-hour-walk-planner-that-runs-on-a-1b-model-kfp</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxxeth0zgnm3ktqniz8qw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxxeth0zgnm3ktqniz8qw.jpg" alt=" " width="800" height="1132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Open outside
&lt;/h2&gt;

&lt;p&gt;At 17:27 I printed the one-page card and left the door. The sunset was at 18:07. The route sent me past nearby green spaces and the low sun came through the trees right as the card suggested.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Describe the light, the printed card in your hand, and one thing the route got&lt;br&gt;
right or wrong. Example shape: &lt;em&gt;"Sunset was at 18:09. I left the house at&lt;br&gt;
17:14 with one sheet of paper. The card sent me left toward the park instead of&lt;br&gt;
right along the main road, and the low sun came through the trees exactly where&lt;br&gt;
it said it would..."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No architecture in this part. Just the walk.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Most "where should I walk" tools want you to keep looking at a screen. You open a&lt;br&gt;
map app, drag around, check the sun, pick a loop, and by the time you leave the&lt;br&gt;
light has moved. I wanted the opposite: a few minutes at the keyboard that end in&lt;br&gt;
a single printed page, and then a phone in your pocket.&lt;/p&gt;

&lt;p&gt;So the output is a one-page route card (big type, a little map) plus a GPX file&lt;br&gt;
for Organic Maps or OsmAnd. The screen is the shortest part of the experience.&lt;/p&gt;
&lt;h2&gt;
  
  
  The rule that makes it work: the model never routes
&lt;/h2&gt;

&lt;p&gt;A 1B–3B model cannot plan a loop through a real street network. It will invent a&lt;br&gt;
road, miss a dead end, and hand you a route that crosses a river. So the split is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The model does language.&lt;/strong&gt; It reads your request ("45 minutes before dark,
trees and quiet") into structured parameters, and it writes the card.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic code does everything numeric.&lt;/strong&gt; &lt;code&gt;astral&lt;/code&gt; computes sunset and
the golden-hour window, &lt;code&gt;osmnx&lt;/code&gt; downloads the walk network and green space,
&lt;code&gt;networkx&lt;/code&gt; builds and scores the loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pipeline is a small LangGraph: &lt;code&gt;intake → sun → weather → map_fetch →&lt;br&gt;
route_builder → critic → card_writer → render&lt;/code&gt;. The &lt;code&gt;critic&lt;/code&gt; can send the route&lt;br&gt;
back for another attempt, loosening the target if it cannot hit the length.&lt;/p&gt;
&lt;h2&gt;
  
  
  Reading the request with a JSON schema
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;intake&lt;/code&gt; node asks the local model (Ollama) for structured output, so even a&lt;br&gt;
small model returns valid JSON:&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;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat_structured&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="n"&gt;state&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_name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Extract walk parameters. Return JSON only.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;state&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_input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntakeParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_json_schema&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;keep_alive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# stay warm until the card is written
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;intake&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IntakeParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_validate_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the model is unreachable or returns junk, the node falls back to defaults and&lt;br&gt;
records a warning. The app always produces a card.&lt;/p&gt;
&lt;h2&gt;
  
  
  Writing the card from facts only
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;card_writer&lt;/code&gt; prompt is deliberately constrained: the model may only use the&lt;br&gt;
verified facts, and every place name must be wrapped in &lt;code&gt;[[double brackets]]&lt;/code&gt; so&lt;br&gt;
it can be checked afterwards.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use ONLY these facts. Do not invent places, landmarks, or plants.
Wrap every place name in [[double brackets]].
Start: ... | Distance: 3.4 km (~45 min) | Sunset: 2026-10-11 18:08
Golden light comes from the 271° . Weather: 29 C, 20% rain
Green spaces on the route: Allah Rakha Park, Bagh-e-Lyari
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then a check pulls every &lt;code&gt;[[name]]&lt;/code&gt; back out and compares it to the OSM list:&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;unknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;unknown_names&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;card_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;place_names&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;unknown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;warnings&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown place names: &lt;/span&gt;&lt;span class="si"&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="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;)&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That check is the difference between "the model wrote a nice card" and "the model&lt;br&gt;
wrote a nice card that sends you to a park that does not exist."&lt;/p&gt;

&lt;h2&gt;
  
  
  What went wrong
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The 1B model invented a place.&lt;/strong&gt; On one run &lt;code&gt;llama3.2:1b&lt;/code&gt; wrote a name that
was not in the OSM data. The bracketed-name check caught it and logged a
warning instead of shipping it. Not every run — the honest number is in the
table below.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OSMnx drops latitude/longitude when it saves a projected graph.&lt;/strong&gt; The GPX
export came out with empty coordinates until the loader inverse-projected the
&lt;code&gt;x&lt;/code&gt;/&lt;code&gt;y&lt;/code&gt; node attributes back to WGS84.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;weasyprint&lt;/code&gt; would not install on Windows.&lt;/strong&gt; I print the HTML from Edge
headless (or a browser) instead, and treat the PDF as best-effort.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[FIELD TEST — add anything the walk itself exposed: a dead end, a retraced&lt;br&gt;
segment, a muddy path, the light arriving earlier than the card said.]&lt;/p&gt;

&lt;h2&gt;
  
  
  The model comparison
&lt;/h2&gt;

&lt;p&gt;Same request, same start point, same map — only the model changes. The router has&lt;br&gt;
no LLM, so route quality is identical; the interesting columns are the&lt;br&gt;
hallucination count and the card length.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Pace read&lt;/th&gt;
&lt;th&gt;Words&lt;/th&gt;
&lt;th&gt;Hallucinated names&lt;/th&gt;
&lt;th&gt;Length error&lt;/th&gt;
&lt;th&gt;Peak RAM&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;qwen2.5:3b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;normal&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0.3%&lt;/td&gt;
&lt;td&gt;259 MB&lt;/td&gt;
&lt;td&gt;106 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;qwen2.5:1.5b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;brisk&lt;/td&gt;
&lt;td&gt;69&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;4.4%&lt;/td&gt;
&lt;td&gt;260 MB&lt;/td&gt;
&lt;td&gt;16 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;llama3.2:1b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;slow&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;9.5%&lt;/td&gt;
&lt;td&gt;274 MB&lt;/td&gt;
&lt;td&gt;76 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;template (no model)&lt;/td&gt;
&lt;td&gt;normal&lt;/td&gt;
&lt;td&gt;55&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0.3%&lt;/td&gt;
&lt;td&gt;273 MB&lt;/td&gt;
&lt;td&gt;65 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All three fit under 0.5 GB of model memory. The 3B read the pace correctly and&lt;br&gt;
produced the shortest, most on-target card; the smaller models misread the pace,&lt;br&gt;
which moves the target length and the length error. Full columns live in&lt;br&gt;
&lt;code&gt;eval/results.csv&lt;/code&gt;; the harness is &lt;code&gt;eval/compare.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The whole point: the screen should lose.&lt;/p&gt;




&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ollama structured outputs — &lt;a href="https://docs.ollama.com/capabilities/structured-outputs" rel="noopener noreferrer"&gt;https://docs.ollama.com/capabilities/structured-outputs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;"Ollama Structured Outputs in Practice — Getting Type-Safe JSON from Local LLMs
with Pydantic" — &lt;a href="https://dev.to/jangwook_kim_e31e7291ad98/ollama-structured-outputs-in-practice-getting-type-safe-json-from-local-llms-with-pydantic-m38"&gt;https://dev.to/jangwook_kim_e31e7291ad98/ollama-structured-outputs-in-practice-getting-type-safe-json-from-local-llms-with-pydantic-m38&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;"Your LLM Returns JSON That Isn't JSON: A Robust Structured-Output Pipeline for
Local Models" — &lt;a href="https://dev.to/syed_anwar/your-llm-returns-json-that-isnt-json"&gt;https://dev.to/syed_anwar/your-llm-returns-json-that-isnt-json&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
