A Builder’s Odyssey

Building Wren:How a Morning Brief Script Evolved into a Local Agent OS

I started with one question — how much real work can a personal AI assistant handle on local hardware, without shipping your daily life through a cloud API?


To answer it, I spent the last few weeks building Wren, a local-first AI agent living on my M4 Pro Mac Mini and powered by Google’s open-weight Gemma 4 model via Ollama.

What started as a handful of scheduled Python scripts to organize my calendar has morphed into an always-on personal operating system. It hasn’t been a straight line. Local models fail in frustrating ways, and making one dependable takes real software plumbing. Here is how Wren started, where Wren stumbled, and how Wren grew into the system running on my desk today.

Phase 1: The Origin

Wren’s very first commit was basic. Wren had a single, unglamorous job: run a scheduled daily task to pull my workout activities from Strava, add them to Google Calendar, and color-code the schedule. I like to keep a strict visual taxonomy on my schedule. Workouts, meal prep, AI research, and coding sessions each get their own color so I can scan my day at a glance. From there, it felt natural to extend that calendar plumbing into a unified morning digest, saving me from clicking across five different tabs with my first cup of coffee.

Over the next few weeks I expanded Wren’s scope into a consolidated morning brief:

I also used a web search tool (Tavily) to scrape AI headlines at first, then scrapped it. Curated daily newsletters deliver far better content without burning extra API calls or context space.

I built a simple loopback web chat interface so I could talk to Wren from my browser. At this point Wren wasn’t really an “agent” in any deep sense. Wren was a bundle of Python API scripts using a local LLM as a glorified text formatter.

Phase 2: The Limit of Local Logic

Running Gemma 4 locally on 48GB of unified memory is fast, but small open-weight models have limits that show up the moment you step outside simple Q&A:

Making a local agent dependable is a systems engineering problem.

I pulled the LLM completely out of tasks that ordinary software handles better. Date math went into a shared Python helper, Strava got a direct API integration, and the model stayed focused on what it’s good at: intent routing and context synthesis.

To keep Gemma 4 running smoothly inside its tight local context window, I put three rules in place:

Phase 3: Memory, Skills, and Asynchronous Push

A chatbot that forgets everything the moment you close the browser tab isn’t an agent. Wren needed persistent state, reusable execution patterns, and a way to reach me when I wasn’t staring at a terminal. Three capabilities:

Phase 4: Expanding into a Personal Testbed

Once the server mechanics were stable, Wren became my testbed. Whenever I hit a repetitive research task or product evaluation loop, I built a tool for it. Instead of forcing open-ended agentic behavior, I leaned into structured pipelines designed around small-model constraints.

Wren's system map: a radial dashboard with Wren at the centre, ringed by skills, memory, routines and applications.
The system map. A single-page radial dashboard of every integration point, schedule, memory tier, and tool path, in real time.

Phase 5: The Daily Learning Loop and LLM Wiki Sync

Rather than sitting down every evening to journal what I learned or built, I wanted Wren to process my daily digital footprint unattended. Every night, background tasks review the prior day’s Chrome history, liked YouTube videos, and AI chat sessions to extract the core takeaways.

Chat was the hard part. Neither Claude nor Gemini offers an API for pulling conversation history out of their consumer apps. To keep the workflow local-first and ToS-compliant, Wren reads what lands on local disk:

Gemma 4 turns the cleaned transcripts into an Accomplished / Learned summary for each session, and an LLM Wiki Sync task writes structured markdown files into my Obsidian vault.

A Daily Synthesis routine runs after the learning tasks finish. It compares yesterday’s activity against what’s already in the vault and pushes a nudge when the two connect across domains — such as flagging when a liked YouTube video matches a note already stored in the vault.

Lessons from the Bench

Building an autonomous local agent on consumer hardware forces you to throw out cloud-scale assumptions and get pragmatic about architecture. After dozens of edge cases, a few hard rules emerged:

  1. Let Python do the heavy lifting. Don’t spend LLM tokens on orchestration, file manipulation, or date calculations. Deterministic code handles the mechanics; the model handles judgment and synthesis.
  2. Context space is scarce. Small local models perform well when fed tight, clean inputs; flooding them with raw terminal dumps or unused tool schemas invites immediate hallucinations.
  3. Safety needs human boundaries. Atomic file locks, explicit permission gates, and mobile confirmation flows are what make a background agent something I’ll actually let run unattended.

I’ve got a lot more I could say about Wren but this post has gone on long enough. Wren remains a work in progress and something I revisit daily. Every capability I add opens new questions about memory management, context decay, and human-in-the-loop design, and working out those trade-offs is the most engaging part of the build.