This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle.
What I Built
Trailhead is a local-first Streamlit app that turns a few taps into a short outdoor outing. You pick an activity, how long you have, and where you are; it pulls live weather and remaining daylight from Open-Meteo, then asks a locally running open-weight model — Gemma 3 4B via Ollama — for an "outing card": a plain-language route, what to look and listen for this week at this latitude, three off-screen challenges, and a one-line safety note. The card exports as a printable HTML file or a PDF.
Then I asked the Week 2 question: who would actually pay for this?
Hikers won't. Hikers have phones. The person with money to spend and no signal is the person selling the walk — the independent nature guide standing at the trailhead, handing paper to strangers.
So in this story, Trailhead grows one button: "Export a guided-walk packet." Same open-weight engine underneath. It just prints a stack of cards instead of one.
The Customer Who Isn't Real
Mara Okonkwo is invented, but she's the person I had in mind. She runs Foothills Slow Walks, a weekend side hustle: $19 per walker for a 90-minute "listen to the forest" loop in the Blue Ridge foothills. Eight walkers on a good Saturday. One of them, most weeks, comes back the next Saturday.
Her problem wasn't the walk. It was the five minutes before it. She wanted to hand each walker a card with what was happening that week — the first of the spring peepers, the tulip poplars dropping, which birds had just arrived. She'd tried a phone app. It needed a cloud call and the trailhead has one bar of signal. It also wanted her route notes and her location on somebody else's server, which, for a guide whose whole product is a secret route she spent two years finding, was a non-starter.
So: a product that runs where she works, keeps her route private, costs nothing per card, and spits out something she can hand to someone with no phone at all.
Demo
In the story: Mara opens the app on a laptop in the passenger seat, types Slow Walk — Great Falls Loop, 90 minutes, 8 walkers, hits Export packet, and thirty seconds later the printer spits out a single letter-size page: six cards, each with the same route but a slightly different "challenge of the day," cut lines and all. She hands them out with a pen.
Code
How I Built It
The engine (real). The model is constrained to a JSON schema and validated with Pydantic, so the output is structured instead of prose I have to parse:
response = client.chat(
model=OLLAMA_MODEL, # default: gemma3:4b
messages=[{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": prompt}],
format=OUTING_CARD_JSON_SCHEMA, # Ollama constrains generation
options={"temperature": 0.3},
)
data = json.loads(response.message.content)
card = OutingCard(**data) # Pydantic validates
If validation fails it retries once; if Ollama is unreachable it falls back to a template card, so the app never dead-ends in front of a customer.
The packet (the story's one new idea). Instead of rendering one card, the export loops over n walkers, generates a card per walker with a shared route but a varied challenge, then tiles them six-to-a-page for cutting:
cards = [generate_card(activity, route, i) for i in range(walkers)]
pdf = TrailheadPacket(start_with_6_cards=True)
for card in cards:
pdf.add_cutout_card(card) # 2 x 3 grid, letter size
pdf.output("slow_walk_packet.pdf")
Everything else (real). Open-Meteo's geocoding and forecast APIs are free and keyless, so the only network call carries a city name or a coordinate. fpdf2 handles the PDF, render_html gives a print-CSS fallback, and SQLite stores past packets so Mara can reprint last week's without regenerating it.
Stack: Python 3.15, Streamlit, httpx, the official ollama client, Pydantic, fpdf2, SQLite. No Node, no build step, no custom JavaScript.
Why Does Open Innovation Matter?
For a side hustle, "why open" stops being philosophy and becomes the margin.
-
It runs where the work happens. Generating a packet is local inference against a local
ollama serve. A closed API would strand Mara at the trailhead with one bar of signal — the exact place the product has to work. - Her route stays hers. The only thing that ever leaves the laptop is a city name to a keyless weather API. No account, no telemetry, no server holding the route she spent two years finding.
- The math only works because inference is free. At $19 per walker, paying per-token for eight cards a session eats the side hustle. Local inference has no per-request cost, no quota, no pricing page that moves under her.
-
She can tune it to her woods.
OLLAMA_MODELswaps the brain in one env var; a fine-tune on her route's species would make the seasonal highlights better than any general-purpose API knows how to be.
The open part isn't a talking point here. It's the whole reason the product clears a price a real person would pay.
The $19
In the story, Mara's first packet costs her nothing to produce and sells for $19 as part of a Saturday walk. She doesn't pay for the software. She pays — the second time — with a request.
"Can it know my loop's birds better?"
Which is, it turns out, a feature request an open-weight model can actually grant.
My Agent Session
Prize Categories
I'm entering Best Use of Gemma — the card generator is Gemma 3 4B running locally through Ollama, constrained by a JSON schema and validated with Pydantic.
Top comments (0)