Is an LLM even the right tool for the job here?
Prediction market historic data will mostly be tabular. Each outcome will have a number of discreet features associated with it, natural or engineered.
Wouldn't a gradient boosted tree approach work better in this domain? xgboost, lightgbm etc.
Or, if a neural network must be used, then one specifically tuned for tabular data work, like TabPFN, might be a better choice.
Using an LLM here just feels like the wrong tool choice.
[1] PriorLabs/tabpfn
I let an open model delete 1,242 of my saved articles. On purpose. I feel lighter.
---
title: I let an open model delete 1,242 of my saved articles. On purpose. I feel lighter.
published: true
description: Unpile is a 100% local read-later triage agent. TabPFN decides which saved articles you will actually read, Gemma writes the digest, offline and free.
tags: devchallenge, hf26challenge, ai, opensource
---
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
I had 1,247 articles saved "for later." This week I let a model on my laptop throw almost all of them away, and I have never felt lighter.
Let me tell you why that was so hard, and why I would do it again.
"Read later" is the most optimistic lie in software. Every tab I save is a tiny promise to a future version of me who does not exist, the one with a free Sunday and a cup of tea and nothing better to do. That version is never coming. So the pile just sits there, 1,247 promises deep, and taxes me a little guilt every single time I open a new tab. I was not keeping those articles. They were keeping me.
The challenge this week, "Slow and Steady," asks for something that rewards laziness: channel your inner sloth, build the thing that does the work so you do not have to. So I built the one thing I was too afraid to do by hand. An agent that reads the whole pile overnight, on my own laptop, with the Wi-Fi off, learns which handful I will genuinely read, and then does the scary part for me: it deletes the rest. No cloud. No account. No cost. No more guilt.
It is called Unpile. On the demo pile it reads 14 saved items, keeps the 5 worth my morning, flags 1 maybe, and silences 8, handing back 5.5 hours of reading time I was lying to myself about. Point it at a real 1,200-item backlog and it quietly clears years of guilt while you sleep.
---
What I Built
Unpile is a local triage agent for your read-later backlog.
You point it at an export (Pocket, Instapaper, browser bookmarks, a CSV) and it does four things, all on your machine:
1. Learns your taste from your own history of what you actually read versus what rotted in the pile.
2. Decides every item: keep, skim, or drop, each with a calibrated probability that you will read it.
3. Writes a calm two-line morning digest of only the keepers.
4. Silences everything else, so you wake up to five good things instead of a wall of guilt.
The effort it saves is the whole point of the challenge. You stop being the triage system. You stop scrolling a backlog deciding, item by item, "do I care about this?" The model does that boring, repetitive judgment call thousands of times and only taps you on the shoulder for the handful that survive. That is the sloth philosophy in one line: it does the work so you do not have to, and you get your attention back.
Who gets to be lazier? Anyone with a doom-pile of unread tabs. Which, let us be honest, is every single person reading this.
---
Demo
Live, in your browser (no setup, real baked model output): simplynadaf.github.io
Video walkthrough: watch on YouTube
{% embed youtu.be %}
The 60-second walkthrough goes end to end: the open-source repo, then the real pipeline running in a terminal (the reading history TabPFN learns from, the keep/skim/drop call with a reason for every item, the local Gemma digest, and the honest held-out scorecard), then the live site. Nothing is staged; the numbers on screen are the actual program output.
!Unpile triaging a read-later pile: 5 kept, 1 maybe, 8 silenced, 5.5 hours reclaimed
And here is the triaged pile itself: five keepers on the left (each with the reasons it survived and a one-line Gemma digest), one borderline maybe in the middle, and the eight it silenced on the right, the 11pm two-hour video essay, the "someday build a cabin" photo essay, the tabs-versus-spaces flamewar.
!The keep, skim, and drop columns with probabilities and reasons
The whole thing runs on a plain CPU. The numbers on the page are the real TabPFN-v2 and Gemma output, frozen into the static site so the demo cannot break in front of you; toggle any item and an in-browser mirror of the model re-decides live.
---
Code
{% github simplynadaf/unpile-read-later-triage %}
---
How I Built It
Two open-weight models, one job each. Neither is decoration; take either one out and the project stops working.
TabPFN-v2 is the decision brain
TabPFN (Prior Labs) is an open-weight tabular foundation model. You do not train it. You hand it your history as context and it predicts in a single forward pass. For Unpile, the history is a table of saved items with the signals you know the moment you save something (source, topic, estimated read time, how stale it is, how many times you reopened the tab, whether it is an actionable how-to, how buried it is) and one honest label: did you ever actually read it?
Prior Labs specifically favors TabPFN used inside a wider prediction agent, not as a bare .predict() call. So Unpile wraps it in a real agent loop:
# predict P(you read it) for the whole pile in ONE CPU forward pass
probs = self._proba(items)
for item, p in zip(items, probs):
action = self._decide(p) # keep / skim / drop from a tunable keep budget
reasons = self._reasons(item) # plain-language "why", so the call is auditable
... # keep the few, flag the maybes, silence the rot
It predicts, decides an action, explains that action in plain language, and then reports honest held-out metrics on itself. That last part matters, and I will come back to it.
I used TabPFN-v2 on purpose: it decides the whole pile in a single CPU forward pass, no GPU and no training run, which is exactly what lets Unpile run overnight on the laptop you already own.
Gemma 3 is the writer
Gemma 3 runs locally through Ollama and writes the morning digest. It is given the keepers and their probabilities and told to never invent an item. If Ollama is busy or the machine is offline, a deterministic fallback writes a correct digest anyway, so the summary always arrives:
def write_digest(keepers):
try:
return gemma_via_ollama(keepers) # calm two-line morning note, local
except Exception:
return rule_based(keepers) # never blocks your morning
The stack is FastAPI, a synthetic-but-documented dataset, a single-file no-build UI, and GitHub Pages for the live demo. All CPU, all local.
---
Why Does Open Innovation Matter?
Your reading list is a confession. It leaks your job, your health, your politics, the thing you are quietly trying to learn. That is exactly the data I refuse to send to someone else's server, and it is the reason this had to be open.
- Your history never leaves the laptop. A closed API would need every row uploaded. TabPFN and Gemma run on-device, so it stays with you.
- It works with the Wi-Fi off. Open weights mean the overnight triage does not depend on a connection, a login, or a vendor being awake.
- It is free, at any scale. Triaging a 1,200-item backlog on a per-call API is a real bill. On open weights it is zero, so I can run it nightly and never think about cost.
- It learns me, not the average. Retrain the decision on my own labels and it mirrors my taste. A closed, general model cannot be bent to one person's weird pile the way an open one can.
A closed API could summarize an article. It could not become a private, offline, free thing that learns my specific reading habits and keeps running on hardware I already own, long after any free tier would have expired. That is the part only open makes possible, and it is the entire reason Unpile exists.
---
The Lazy Payoff
Here is what this actually bought me, and it was not time. It was permission to let go.
I used to be the triage system. Every few days I would open that folder, feel the weight of 1,247 unread promises, scroll a bit, close it, and feel slightly worse than before. The backlog was not a to-do list. It was a slow-drip guilt machine I had built for myself, one hopeful tab at a time. What I could never do was the obvious thing: just delete them. Deleting felt like admitting I would never become the person who reads 1,247 articles. So I never did. The pile only grew.
The model does not have that hang-up. It looked at my own history, decided which five were real, and threw the rest away without a flicker of guilt, because it does not have any. I did not read 1,242 items this week. I did not even look at them. And the folder that used to make me wince now makes me feel nothing at all, which, after years of that quiet tax, feels like a lot.
Quantified in the only currency the challenge cares about: 8 of 14 items silenced with zero input from me, and 5.5 hours of reading time handed back, time I was lying to myself about anyway. Point it at a real 1,200-item backlog and it is clearing years of that guilt while I sleep. The sloth philosophy, literally: move slow, conserve energy, let the boring, frightening part happen without you.
---
The Honest Take
Here is the scorecard, measured on a held-out slice of 240 saved items the model never saw, because a number I cannot check is just a vibe.
- Precision 0.60: when Unpile surfaces something, I actually read it about 60% of the time, against a 36% base rate in the raw pile. It nearly doubles the odds that the thing in front of me is worth it.
- Lift 1.66x: the kept pile reads 1.66 times better than a random grab from the backlog.
- Silenced 58%: it auto-archives well over half the pile with no input from me. That is the laziness, quantified.
- Reclaimed 5.5 hours on the 14-item demo alone. Scale that to a real 1,200-item backlog and the model is doing days of triage you were never going to do yourself.
And now the number I am putting right next to the good ones, on purpose:
- Wrongly dropped 44%. At this setting, of the items I genuinely would have read, it also silenced about 44% of them. The most painful miss on the demo pile is "this week in AI (issue #214)" at 37% confidence: a fresh newsletter in a topic I follow, and it landed just under the keep line. It got silenced. On another morning I would have wanted it.
I am not hiding that. Unpile is not magic; it trades recall for a calm morning. But the fix is a dial, not a lie: loosen one threshold (UNPILE_KEEP_T) and you recover more of those near-misses at the price of a slightly noisier digest. I would rather ship the honest trade-off, with the failure case named out loud, than a demo that pretends false negatives do not exist.
---
Prize Categories
- Best Use of TabPFN (featured): TabPFN-v2 is the decision brain, used as a real prediction agent (predict, decide, explain, measure) over a personal CSV, with honest held-out metrics, exactly the "prediction agent" pattern Prior Labs favors over a bare classifier.
- Best Use of Gemma (featured): Gemma 3 runs locally via Ollama to write the morning digest, grounded strictly on the model's own output, with a deterministic offline fallback so it never hard-fails.
Built new for this challenge (Oct 19 to 25). It reuses my own local-AI patterns from earlier weeks, re-applied to a new problem, dataset, agent loop, and UI, disclosed in the README per the credit rule.
---
Thanks for reading all the way down. You just did something your backlog never let you do: you finished. Now go let a model read the rest for you.
20 reactions · 12 comments
TabPFN 3.5 — модель работы с табличными данными, умеющая в Фурье-препроцессинг, тестируем по SDD (OpenSpec + OpenCode)
Наконец-то приехала фундаментальная модель, заточенная под работу с табличными данными и уже в базе умеющая препроцессить сырые данные. И у меня дошли руки ее потестировать.
Технический отчёт: arxiv.org
Обзор отчёта: arxiviq.substack.com
Код (pip-пакет tabpfn): PriorLabs/TabPFN
Веса модели: huggingface.co
А у меня как раз такие данные, которые идеально подходят для теста этой модели: записи отсчетов измерений напряжения с умной розетки в разных сценариях энергопотребления. Нюанс этих данных в том, что их, конечно, можно интепретировать как временные ряды, но гораздо эффективнее извлекать из них FFT-спектры и работать уже с частотным представлением. В посте двухгодовалой давностилучшие результаты показал ансамбль катбустов в составе фреймворка Light Auto ML - именено после предварительного процессинга табличных данных и переходом от временного представления (Time Series) к частотному через быстрое преобразование Фурье (FFT).
Увы, руки уже не столько мои, сколько кодингового агента, но на этот раз я взял на вооружение SDD (Specification-Driven Development) в реализации OpenSpec. Из прошедших через мои руки бесплатных и условно-бесплатных альтернатив самому популярному агенту на букву "К" я остановился на OpenCode как самой продвинутой на текущий момент (из тех, что успел "пощупать"). Сразу оговорюсь - многое зависит от того, какая конкретно модель используется внутри OpenCode, буквально вчера я решал другую задачу с помощью MiniMax 3.1-Flash, и пришлось править две ошибки, а сегодня GLM-5.3-Flash меня приятно удивила быстротой, точностью выполнения моих инструкций - и отсутствием ошибок (кроме одного нюанса, который был обнаружен экспериментальным путем). Ну и, конечно, следование подходу SDD.
Результат будет хз, если не было... спецификаций
Сам подход, безусловно, не нов. Но он предоставляет мощную подпорку для работы белковых разработчиков с искусственными нейронными сетями: во-первых, он заставляет четко формулировать задачу. Кажется очевидным, но давайте будем честны в ответе на вопрос - а мы сами-то всегда ли четко артикулируем то, над чем работаем? Для тех, кто не застал СССР, хочу напомнить старый советский анекдот, отражавший дефицит суперкомпьютеров в Советском Союзе:
Американский физик спрашивает у советского: "Как вам удается достигать таких высоких результатов в науке, ведь ваши компьютеры сильно отстают от наших?" На что тот отвечает: "Все просто: вы садитесь за компьютер и думаете над каждым его ответом, а мы сначала думаем, а потом уже садимся за компьютер".
Тут тоже самое. Сначала подумай, какую задачу ты хочешь решить. Какие есть ограничения. Какие ожидания. И только после этого запускай команду /opsx-proposal или /openspec-proposal.
Provided arguments: ## Цель: протестировать новую модель TabPFN-3.5 на данных о сценариях потребления энергии пользователями.
Задача: создать .ipynb ноутбук
Ресурсное ограничение: .ipynb ноутбук должен работать в Google Colab
Описание TabPFN-3.5:
Информацию о модели можно взять из статьи: arxiv.org и ревью к ней arxiviq.substack.com
Код можно взять в репозитории PriorLabs/TabPFN
А саму модель из huggingface.co
Я не вижу размера модели на HF, поэтому первый же вопрос: требуется ли GPU или можно запустить на CPU?
Второй вопрос: если все-таки требуется GPU, влезет ли она в T4, доступный в Google Colab?
Данные для проверки
Пример загрузки данных из монтируемого Google Drive описан в ноутбуке TimesFM3_DeepSeek.ipynb - он лежит в папке проекта
Если требуется предобработка данных - смотри на структуру данных в этом ноутбуке.
Дополнительно: избегай установки лишний пакетов - минимизируй зависимости.
После генерации ноутбука проверь на наличие лишнего кода, удаляй неиспользумый код и импорты
Каждую ячейку снабжай подробным комментарием: что здесь проиходит и зачем это нужно.
Также не забывай снабжать описания классов docstring и комментариями.
Разбивай секции markdown-ячейками.
После того как агент отработает, стоит проверить артефакты генерации спефикации в папке /openspec/changes - ищем там proposal.md и tasks.md.
Второй аспект полезности SDD: когда у агента переполняется окно внимани, он сжимает (суммаризирует) текущую сессию - и перезапукается. При перезапуске он подгражует себе Guardrails и прочие настройки системного промта (при желании их можно найти и подшаманить), а также саммари контекста сессии и спецификации. Если вы используете локальные модели с небольшим окном контекста, то перезапускаться агент будет часто. Поэтому чем давать комментарии по ходу исполнения, которые будут как-то суммаризироваться, лучше сразу записать их в спецификацию.
У нас почти все получилось. Но всплыл нюанс:
TabPFNLicenseError: TabPFN requires a one-time license acceptance to download
model weights for local inference, but no interactive terminal
is available.
Агент утверждает, что этого не было в документации:
Interesting: the README/HF card I fetched didn't mention this — but the FAQ had "How do I use TabPFN without an internet connection?" and "How do I get access to TabPFN-2.5/3/3.5?" questions. The error message explains the flow: register at ux.priorlabs.ai, accept license, copy API key, set TABPFN_TOKEN env var before fit().
Options:
1. User accepts license once at ux.priorlabs.ai, gets API key, sets os.environ["TABPFN_TOKEN"] in a Colab cell before evaluation. I should update the notebook to handle this: add a config cell (early) where user pastes their API key or it checks TABPFN_TOKEN, with clear Russian explanation, without breaking the "Run All" neutral flow.
2. Alternative: check if HF token works — the error mentions try_browser_login(gui_url, hf_repo_id=...). In old tabpfn versions, downloading from HF worked anonymously (the model card earlier versions had no gating). Apparently for 3.5 the package introduced license-gating with API keys.
Но, на самом деле, агент не совсем прав - веса можно скачать напрямую с HuggingFace, они там реально выложены и их можно скачать без авторизации. Но для этого надо влезть в импортируемый пакет tabpfn и переделать загрузку весов. Агент пошел по первому пути, предложив зарегаться на сайте Prior Labs (поставщиков пакета), получить API Key и добавить его в секреты Colab-ноутбука. Аплодирую Prior Labs - молодцы, грамотно придумали способ сбора статистики загрузок, независимый от HF. Ну а для себя - отмечу еще идин пункт в будущих спефикациях.
Ну, собственно, все. Модель отработала:
Матрица ошибок классификации
И модели удалось превзойти по макроусредненной F-мере baseline: ансамбль катбустов (с которого все начиналось) - пусть и немного, всего на 1 процент. Пожалуй, запишу себе модель в список проверенных инструментов для классификации табличных данных.
Код опубликован в репозитории Archelephant/TabPFN_w_OpenSpec
З.Ы. А вот знаете, что я забыл добавить в спецификацию перед пушем в Github? Можете накидать мне в комментариях...
I Built an Open-Weight AI That Prices Etsy Shops, On Your Laptop
---
title: "I Built an Open-Weight AI That Prices Etsy Shops, On Your Laptop"
published: true
tags: devchallenge, hf26challenge, tabpfn, opensource
---
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
!PricePilot: price it right, then watch it sell
My friend runs a tiny candle shop on Etsy. Forty-odd listings, a day job, and a pricing
strategy she described to me, without a trace of irony, as "vibes."
She is not wrong to struggle. There is no sticker price for a hand-poured soy candle. The right number depends on the scent, the size, the wax, how long it took, the season, how many photos she shot, how her shop is rated. A dozen little things that interact. Price it $4 too high and it sits until the wax degrades. Price it $4 too low and she is paying Etsy fees to work for free. She has lost real money both ways.
The tools that promise to fix this are closed SaaS products: a monthly fee, and an upload of her entire sales history to someone else's server so they can rent her a number back. For a shop that clears maybe $300 a month, that is a bad trade twice over. There is the cost. And there is handing the one thing that is actually hers (what sells, at what margin) to a stranger's cloud.
So I built her PricePilot: a pricing copilot that runs entirely on her laptop. It predicts what an item will sell for from sold-listings data, then writes the listing. No account, no API bill, nothing uploaded anywhere.
---
What I Built
PricePilot turns one short form into three things a seller can act on immediately:
1. A price with an honest range. Not a single false-precise number but a predicted sell
price and the 10–90% band around it, plus a measured error so you know how much to trust
it.
2. The levers that raise it. It doesn't just score the listing; it tells her *what to
change and by how much*: "offer personalization, about +$5", "list in the Q4 season,
about +$8", "use premium materials, about +$12", ranked by dollar impact.
3. A ready-to-paste listing. Title, description, and eight search tags, written to match
the predicted price.
Who would pay for it: independent Etsy, eBay, and marketplace sellers. The exact "side hustle" person this week is about. The thing it fixes (what do I charge?) is the thing that most directly decides whether the hustle makes money.
---
Demo
🔗 Live demo (fully interactive): simplynadaf.github.io
🎥 Video walkthrough: watch on YouTube
> The hosted demo is interactive end to end: every field is editable and the price updates instantly, powered by an in-browser estimate that mirrors the model. For the actual TabPFN-v2 prediction with Gemma 3 writing the listing, clone the repo and python run.py, fully offline. That is the whole point of PricePilot.
Describe an item the way you'd list it (category, materials, size, hours to make, condition,
photos, season) and PricePilot prices it and drafts the listing in one shot.
!PricePilot result: a predicted price with its 10–90% range, the ranked what-if levers, and a listing with title, description, and tags
---
Code
{% github simplynadaf/pricepilot %}
---
How I Built It
PricePilot is two open-weight models doing one honest job each, locally.
!How it works: you describe the item, TabPFN-v2 predicts the price, Gemma writes the listing
The price: TabPFN-v2 as a prediction agent
Pricing is a textbook small-data tabular problem (a few hundred past sold listings, ten features, one continuous target), which is exactly what TabPFN-v2, Prior Labs' open-weight tabular foundation model, is built for. It predicts in a single CPU forward pass with no per-dataset training.
But Prior Labs explicitly favors TabPFN used inside a wider prediction agent, not as a one-shot regressor, so that's what I built. PricePilot:
- predicts the sell price with a calibrated 10–90% range from TabPFN's output quantiles,
- then runs a small what-if loop: it re-queries TabPFN under single-feature changes a seller actually controls (more photos, personalization, Q4 timing, better condition, premium materials) and ranks them by the dollar delta, all in one batched forward pass so it stays fast on CPU,
- and reports a held-out mean absolute error so every number is measured, not asserted.
On the sample dataset, TabPFN predicts held-out sold prices with an MAE of about $2.90 on items averaging ~$54. That is roughly 5% error, with zero training time. The honesty number is the whole point: she can see how much to trust it.
# the prediction agent, simplified: predict, then re-query to explain the number
mean, low, high = self._predict_one(feats) # price + 10-90% range
preds = self._predict_rows(whatif_rows) # ONE batched pass for every lever
levers = sorted(
(WhatIf(label, round(p - mean, 2)) for label, p in zip(labels, preds)),
key=lambda w: w.delta, reverse=True,
)
The listing: Gemma 3, grounded on the number
A local Gemma 3 model (open-weight, served by Ollama) turns the item and that exact predicted price into a title, description, and tags. It is told the price and told never to invent a different one. The number is always TabPFN's. Gemma just writes the copy around it.
The safety net
If Ollama isn't running, a deterministic template writes a correct listing from the same price, so she is never staring at a spinner. The whole stack (FastAPI, a no-build premium front end, both models) runs on localhost. I verified the offline path by pointing the Ollama host at a dead port and confirming the listing still came back.
---
Why Does Open Innovation Matter?
This is the part that made the project worth building, and every point is something a closed API would have taken away:
- Her sales data stays hers. What sells, at what margin, is her entire edge. PricePilot
never uploads it. A closed pricing tool would turn her shop's history into its training
data.
- $0 per listing. Open weights mean no per-call fee. She can reprice her whole shop every
week and the bill is nothing. A subscription would eat the margin the tool is supposed to
protect.
- It can learn her niche. She can drop in her own exported Etsy sales CSV and the model
fits her corner of the market (soy candles in her price band) where a general API trained
on "everything" is mediocre. The open approach is what lets the long tail have a model that
fits it.
- No lock-in. The listing writer points at any open-weight model Ollama runs; the
predictor can be retrained. She owns the stack, not a line on someone's pricing page.
A frost date, a race time, a candle price: the pattern that keeps winning this Hacktoberfest is the same. A small, open model, running where your data already lives, beats a big closed one you have to pay and trust.
---
My Agent Session
I built PricePilot with an AI coding agent, and the honest story of the build is that the two hard problems were both about trust in the numbers, not wiring. First, TabPFN on CPU was slow enough to feel broken until I batched every what-if scenario into a single forward pass (the per-request time dropped from minutes to seconds). Second, I had to stop the language model from ever emitting its own price, so the agent and I settled on a rule the whole design now rests on: Gemma is told the number and never produces one. The repo's commit history tracks that path from a bare TabPFN spike to the batched prediction agent.
---
My First User
I built PricePilot for a real person: a friend who runs a small candle shop on Etsy and genuinely prices by "vibes." I have not sat her down with the finished build yet (that is my next step, and I will update this post with what she says), so I will not invent a reaction here. What I can say honestly is why I think she, and sellers like her, would pay:
- The pain is the money. Pricing is the single decision that most directly sets whether a
handmade shop earns or loses on each sale. A tool that gives a defensible number, with a
range and a measured error, targets the exact spot where a side hustle leaks money.
- The alternative already costs money. Sellers pay $10–30/month for closed pricing SaaS
that also wants their sales history uploaded. PricePilot does the same job for $0 and keeps
the data on their laptop. "Same outcome, free, private" is an easy yes.
- It answers a question they ask constantly. "What do I charge, and what do I write?" is a
daily question for an active seller. PricePilot answers both in one shot.
My honest take: I would not charge for the current build, because the whole point is that it runs free on the seller's own machine. The thing a seller would actually pay for is the time and the second-guessing it removes, and that is what I will test with her next.
---
Prize Categories
- Best Use of TabPFN: TabPFN-v2 is the core: it predicts the price, provides the
calibrated range, and is wrapped in a what-if prediction agent that re-queries the model
to explain which levers move the number. Accuracy is reported as a held-out MAE (~$2.90), so
the claim is measured, not asserted.
---
*Built with open weights, on a laptop, for a friend who prices by vibes. Made with 🤍 by
Sarvar.*
21 reactions
Turnaround: an open-source hiking buddy that knows when you should turn back, and tells someone if you don't come home
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass
Most hiking trouble isn't dramatic. Nobody falls off a cliff. Someone simply keeps going a little too long because the summit is "just around the corner", the sun sets earlier than they thought, and the only person who knows where they went is themselves.
Two things would fix most of that:
1. Knowing, before you leave, the time you should turn around, based on how fast you actually walk rather than a sign at the trailhead.
2. Someone you trust finding out automatically if you don't come back, without you having to remember to tell them.
So I built Turnaround. You spend about two minutes with it before a hike, then put your phone in your pocket.
What I Built
Turnaround is a hiking companion that runs entirely on your own laptop. Before a hike it gives you three times:
- Turn around by: not at the top or the far end by this time? Head back.
- Back by: 9 in 10 hikes like yours finish before this.
- Sunset margin: how much daylight you have to spare.
Then it does four things:
- Predicts how long you will take, as a range rather than a single guess. An open tabular foundation model (TabPFN) learns from 7,186 real recorded hikes and adjusts to your pace after every hike you finish.
- Briefs you out loud. Gemma 4, running locally, turns the numbers into a short spoken briefing that sounds like a friend who hikes. It's saved to your phone before you leave, so it plays with no signal.
- Watches. When you tap Start, a durable safety timer begins waiting for your check-in.
- Tells someone. If you're well past your back-by time and still haven't checked in, your emergency contact gets an email with your plan, your route and a map link to where you set off. If you then check in late, they get a second email saying you're safe.
No GPX file? You just enter the three numbers every trail page lists (distance, elevation gain and trailhead), and Turnaround plans from those.
Who it's for: anyone who hikes alone or is new to it, and anyone with a parent, partner or friend who worries when they head out.
How it gets you off the screen: the screen part is the beginning and the end of the trip. Plan, listen, pocket the phone, walk. The next time you look at it is to tap Hike complete.
How it works
!How it works: plan, go, check in
Demo
{% youtube eOzc_RNBzMk %}
The video walks through the whole flow: planning a hike, the spoken briefing, starting the trip and the safety timer, and checking in.
Turnaround runs on my laptop, by design (more on that below), so there's no public link. The repo has one-command-per-terminal setup if you want to run it yourself.
Code
{% github CodeNeuron58/Turnaround no-readme %}
MIT-licensed. CI runs typechecks, the app build and two unit-test suites on every push. Everything I claim below has a file in the repo backing it.
How I Built It
Everything runs on one laptop:
- Phone or browser → the app (React + Vite), reached over Wi-Fi or Tailscale
- App → the prediction service (FastAPI + TabPFN + SQLite)
- Prediction service → Gemma 4 (via Ollama) for the briefing, Kokoro for the voice, and the Temporal server to arm the timer and send check-ins
- Temporal worker → the alert and all-clear emails to your contact
The only things that leave it are an anonymous weather lookup (coordinates only) and, if you're overdue, the alert email.
1. Predicting your hike time: TabPFN
The classic hiking-time rule is Naismith's rule: roughly 12 minutes per kilometre plus 1 minute per 10 m of climbing. It's on half the trail signs in the world, and it gives the same answer for everyone.
I wanted a range, and I wanted it to fit the person. TabPFN is an open tabular foundation model: you give it a table of examples and it predicts new rows in context, with no training loop. Crucially for a safety tool, it returns a full predictive distribution rather than one number.
The data is 7,186 GPS-recorded hikes from hikr.org (a public Kaggle dataset, CC0). The features are distance, climb, descent, highest point and the SAC difficulty grade (T1–T6). I held out 1,438 hikes the model never saw and compared it with Naismith:
| On 1,438 unseen hikes | Naismith's rule | TabPFN v3.5 |
|---|---|---|
| Average error | 44.1 min | 34.8 min |
| RMSE | 69.1 min | 54.5 min |
| Real times inside the predicted 90% band | — | 89.5% |
| Hikers back before the "back by" time (P90) | — | 90.4% |
The last row is the one I care about most. A safety tool has to be honest about its uncertainty, not just accurate on average. When Turnaround says "9 in 10 hikes like this are done by 4:40", that turns out to be true for 90.4% of hikes. Average error being 21% lower is a nice bonus.
On a laptop CPU I serve TabPFN v2 by default. It's about 3x faster with nearly identical calibration (89.7%). The v3.5 checkpoint is one environment variable away.
How the prediction becomes decisions:
- Back by = the 90th percentile + your planned breaks.
- Turn around by = the share of that time you should spend heading out, assuming you retrace your steps. Climbing happens on the way out, so steep routes front-load it (Naismith's split, clamped between 50% and 70%).
- Alert = the 95th percentile + breaks + 30 minutes of grace. I deliberately didn't make it the back-by time: your contact should only be emailed when you're genuinely late, not five minutes slow.
Learning your pace. The crowd isn't you. Every hike you finish compares your actual moving time with the model's median for the same route, and the ratios combine into a personal pace factor. It's shrunk toward 1.0 on purpose, so one bad day can't swing the safety timer. A hike that was 40% slower than predicted moves your next estimate up about 12%, not 40%. Hikes where you tapped I turned back early don't count, because a turned-back time says nothing fair about the whole route. All of these rules are in a small, unit-tested module.
2. A promise that survives a crash: Temporal
The scariest bug a safety app can have is a timer that silently dies. If the alert depends on a Node process staying alive for six hours on a laptop, it's not a safety feature, it's a hope.
So the safety timer is a Temporal workflow. One tripWorkflow per hike races a check-in signal against a durable timer set to the alert moment. Sending the email is an activity with retries. A late check-in after the alert triggers the all-clear. I run Temporal's free local dev server with an on-disk database, so timers survive a restart of the server itself, not just the worker.
Then I tried to break it. Each scenario has its workflow history or logs committed in docs/evidence/:
| # | What I did | What happened |
|---|---|---|
| 1 | Checked in on time | Timer closed, nobody emailed |
| 2 | Missed the check-in while the mail server failed | Activity retried; alert went out on attempt 2 |
| 3 | Killed the worker mid-trip, restarted it 25 s later | Alert still fired exactly on the deadline: 90.5 s after start, despite the worker being dead from second 20 to 45 |
| 4 | Drill: missed check-in, then a late check-in | Alert on the deadline, then an all-clear |
| 5 | Killed the Temporal server mid-trip | Timer survived on disk; a check-in sent during the outage reported the failure honestly and landed when re-sent |
Scenario 3 is the whole reason Temporal is here. The promise didn't notice the outage.
This is what your contact actually receives. Both emails below were delivered to my own phone through Brevo, using the same templates and code path the worker uses (sent with the preview command, which is why they're marked [PREVIEW]):
!The alert email and the all-clear email, as they arrived on my phone
The alert says who, which route, when they set off and when they should have been back, with a one-tap map link to the starting point. The all-clear tells your contact they can stand down. Nobody has to decode a log file at 4 a.m.
The app is equally honest when something is wrong. If the timer fails to arm, the trail screen shows a red "safety timer NOT armed" banner with a retry button rather than pretending you're covered. If you check in with no signal, the check-in is saved on the phone and sent the moment it can reach the laptop, and re-sending is idempotent, so a flaky connection can't double anything.
3. A briefing that sounds like a friend: Gemma 4 + Kokoro
Numbers on a screen are easy to ignore. A voice in your ear saying "If you're not at the top by 1:40, turn around. The view will still be there next weekend" is not.
Gemma 4 (E4B) runs locally through Ollama's OpenAI-compatible endpoint. The service hands it the trip's facts (distance, climb, turn-around and back-by times, sunset, rain chance, trailhead) and asks for 4 to 6 short sentences "like a friend who hikes, not a robot", always including the turn-around rule. Kokoro, an open 82M-parameter text-to-speech model, reads it aloud on the same machine. The text and audio are generated once, stored, and saved to your phone while you still have signal.
Gemma is the voice, never the source of truth: every number it speaks comes from the prediction service, and if the sunset time is unknown, the prompt tells it to say so rather than invent one.
The app
React + Vite, three screens: Plan, On trail and Summary. Your phone reaches the laptop over the same Wi-Fi, or over Tailscale on mobile data, so nothing is exposed to the public internet. Weather and sunset come from Open-Meteo, with no API key and coordinates only. Alert emails go through a free Brevo account, and every email is also written to a local outbox as a record.
Why Does Open Innovation Matter?
Think about what a hiking plan reveals: where you'll be, that you'll be alone, and until when. I don't think that belongs on someone else's server, and with open models it doesn't have to.
- Your location stays on your machine. Gemma 4, TabPFN and Kokoro all run on my laptop. A closed AI API would see every trailhead I start from and every hour I'm out alone.
- It costs nothing to run. No subscription, no per-request bill, no key that expires mid-hike. A hiking club could host it for its members on one old laptop or a Raspberry Pi-class box.
- The uncertainty is mine to inspect. With TabPFN's weights and a public dataset, I could measure calibration on 1,438 unseen hikes myself. A closed "estimated time" API gives you a number and asks for trust. For a feature that decides when your family gets an alarming email, I wanted the evidence.
- Everything is swappable. The checkpoint is one environment variable (v2 for speed, v3.5 for accuracy), Gemma could be any model behind an OpenAI-compatible endpoint, and Piper is a drop-in fallback for Kokoro. Nothing in the stack can be deprecated out from under it.
- The data is a commons. The model learns from thousands of hikers who shared their tracks publicly, and gives each new hiker something back.
Where open was genuinely better for me, not just cheaper: calibration. I needed to know that "back by" means 90%, and I could only know that because I could run the model myself on data I could see.
Honest limits. So far I've tested Turnaround at home, with sample routes and missed-check-in drills; taking it on a real trail is next. It's a prototype, not a replacement for telling someone your plan or carrying a satellite messenger in real backcountry. The laptop has to stay awake and online for the alert to send. The model knows hikr.org's mostly Alpine hikers best, and the pace factor exists precisely because you are not them.
Prize Categories
- Best Use of TabPFN: TabPFN predicts each hike's moving time as a calibrated distribution. Its P90 becomes the back-by time, its P95 sets when your contact is alerted, and its median feeds your personal pace factor. On 1,438 unseen hikes it beat Naismith's rule (34.8 vs 44.1 min average error) with 90.4% of hikers back before P90.
- Best Use of Temporal: the safety timer is a durable Temporal workflow that races a check-in signal against the alert deadline, retries the alert email, and sends an all-clear on a late check-in. Tested by killing the worker and the Temporal server mid-trip, with evidence in the repo.
- Best Use of Gemma: Gemma 4 runs locally via Ollama and turns each trip's numbers into a short spoken briefing (voiced by Kokoro) that's saved to your phone before you lose signal.
---
Thanks for reading. If you hike alone, I'd love to hear what would make you actually use something like this, and what time you'd want to be told to turn around. 🥾
2 reactions · 3 comments
Frostline: what to plant this week, from your local frost dates
Most garden advice is a fixed calendar. But the right week to sow a carrot in Portland is not the right week in Minneapolis. A calendar does not know that. Your frost dates do.
Frostline asks for your location and tells you exactly what to sow this week, from your own last-spring and first-fall frost dates. The screen is the shortest part. Read the plan, close the laptop, go plant.
- Live demo: frostline-lime.vercel.app
- Code: zkasuran/frostline
What it does
Type a US city or tap "use my location". Frostline shows your two frost dates, then a sow-this-week list drawn from 29 common vegetables and herbs, each with a plain reason like "sow kale now, it takes a light frost and keeps going into the cold". It reads at a glance and needs no sign-in.
Open-source AI is the core, not the garnish
Two open models do the real work.
Frost dates come from TabPFN, an open tabular foundation model from Prior Labs. I trained it offline on 6,784 NOAA weather stations to predict the last-spring and first-fall 32F frost dates from latitude, longitude and elevation. On 1,357 stations held out of training it is accurate to 6.9 days for the last spring frost and 9.7 days for the first fall frost, which beats a nearest-station baseline (8.7 and 10.8 days) on both.
The write-up comes from Gemma, Google's open-weight model. The live site writes it with Gemma 3 served openly through OpenRouter, with the built-in narrator as the instant fallback so the page never blanks. The result is cached per place and day, so a reload is immediate.
Why open matters here, concretely:
- It runs cheap. Gemma 3 costs a fraction of a cent per plan, so a free gardening tool stays free.
- Your location stays yours. Your coordinates go to the Frostline server only, where they are matched against the baked grid. They are never forwarded to a model vendor and nothing is stored. When Gemma writes the plan it sees a coarse label (your city name or just "your location") and the frost dates, never your exact position.
- You can swap the model. Retrain the frost model on your own stations or point the advice at any open model with one environment variable.
- It can run offline. Open weights mean the whole pipeline can run on a laptop with no internet, which is the point of a tool you use outside.
How it works
TabPFN needs PyTorch, so it never runs on a request. I bake it once, offline, into a 0.25 degree US grid of 16,353 points and ship that as a small static file. At request time a tiny lookup interpolates your location against the grid, a deterministic planner turns your frost dates and today into the sow-this-week list, then Gemma writes it up. No model sits in the hot path for the frost dates, so the plan is instant and the site cannot blank.
What is real and what is simulated
I will not dress this up:
- Frost dates are real TabPFN predictions from NOAA 1991-2020 normals. The error above is measured on held-out stations.
- The plan is a real deterministic function of your frost dates and today.
- The advice prose is written live by Gemma 3, with the built-in planner as the instant fallback. The app labels which one wrote it.
- Frost-free places like Miami and Key West are labelled from the measured NOAA freeze probability of the nearest stations, not from a guessed date, so the app never pretends a frost-free spot has a hard frost. The Reports page shows all of it.
The two partner categories
- Best Use of TabPFN: frost-date prediction is a clean small-tabular regression, exactly what TabPFN is for. It beats the obvious baseline. The accuracy is published in the app and reproducible from bake/train_tabpfn.py.
- Best Use of Gemma: Gemma writes every plan on the live site, grounded on a strict facts-only prompt so it never invents a date or a crop, with a deterministic fallback so the product is never at the mercy of the model.
Built to be attacked
One command gates the whole thing (./verify.sh): strict types, zero-warning lint, tests, a production build and a clean dependency audit. The site ships a strict nonce Content-Security-Policy, security headers, validated inputs and a route error boundary. The threat model is in the repo.
Try it
Open frostline-lime.vercel.app, type your city and see what you could put in the ground this week. Then go outside.
---
AI assistance (Claude) was used to build Frostline. The design, the model choices and the licence decision are mine. Every number here is measured against the code and the live site so you can check it yourself.
2 reactions
I built an offline AI that knows your last frost date, no internet, no API
---
title: I built an offline AI that knows your last frost date, no internet, no API
published: true
description: An open-weight tabular model forecasts your last spring frost and a local Gemma writes the planting advice. Fully offline, no account, $0 to run.
tags: devchallenge, hf26challenge, ai, opensource
cover_image:
canonical_url:
---
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass
The most useful number in a vegetable garden is the last spring frost date. Get it wrong by a week and one cold night turns your tomato seedlings to mush.
Every tool that gives you that number has the same flaw. It lives on a server. You look it up on your phone, standing in the one corner of the allotment that gets a bar of signal, hoping the page loads before the rain starts.
So I built FrostWise: it predicts your last frost and tells you what to plant, and it does the whole thing on your laptop with the Wi-Fi off. Two open-weight models, no API key, no account, nothing leaves the machine.
I built it for a specific person: my friend who keeps a plot at a community garden on a hill where the signal drops to nothing. Every spring she texts me "is it safe to plant yet" because she cannot load a frost-date site from the plot itself. FrostWise is the answer she can keep on her own phone and open with no bars.
What I Built
FrostWise answers one question honestly: when does the cold let go where you are, and what should you do about it.
You pick a location (or type your own climate numbers), choose a crop, and it returns three things:
- A date. Your predicted last spring frost, with an honest range, not a fake single-day promise.
- The advice. Plain language for your exact crop. Wait until after the frost for tender things like tomato and basil. Sow a few weeks early for hardy things like peas and kale.
- A reason to trust it. The number comes from a model you can inspect and retrain, and the range tells you the risk.
It gets people off the screen in the most literal way. The screen is the ten seconds you spend before you walk outside and put a seed in the ground. The whole point is to make that part short.
Who it is for: anyone with a patch of soil and a spotty signal. Community plots, hillside allotments, a herb bed at a trail-head cabin. The places where a cloud API is useless are exactly where people garden.
!FrostWise homepage: the headline Know when the frost lets go over a soft midnight-galaxy starfield, with Plan my garden and How it works buttons
Demo
Try it now: d2damz5gbd2rbh.cloudfront.net
That hosted link is a static site (S3 plus CloudFront, near zero cost) that serves real, pre-computed TabPFN-v2 and Gemma results for the preset cities, so you can click through actual model output. The live models themselves run on your own machine. For custom climate input, fully offline, clone the repo and run python run.py.
Here is the full flow across three very different climates: Miami (effectively frost-free), Chicago (a real May frost), and Fargo (frost that lingers into summer). Same code, three honest answers.
Here is what one answer looks like: a predicted last frost, the honest range around it, and planting advice written locally by Gemma for the exact crop.
!FrostWise result for Chicago: a predicted last spring frost of May 20, likely between May 15 and May 26, with an amber advice card for tomato written locally by Gemma
The frost date animates in, then a local Gemma model writes the planting advice live. Nothing in that video calls out to the internet.
Code
{% embed simplynadaf/frostwise %}
Clone it, python run.py, and it is on localhost:8077. The first forecast caches the model weights once; after that you can pull the network cable and it still works.
How I Built It
The whole thing is two open-weight models doing one honest job each, locally.
!FrostWise architecture: the browser sends a location and crop to a local server; TabPFN-v2 forecasts the last-frost day on CPU; Gemma 3 in local Ollama turns that date into advice; a deterministic rule covers the offline fallback; nothing leaves the machine
The forecast: TabPFN-v2
TabPFN is a tabular foundation model from Prior Labs. It is the strange and wonderful part. Instead of training a model on my frost data, I hand it the data as context and it predicts in a single forward pass. No training loop, no hyperparameter search, no GPU.
from tabpfn import TabPFNRegressor
from tabpfn.constants import ModelVersion
reg = TabPFNRegressor.create_default_for_version(ModelVersion.V2, device="cpu")
reg.fit(X_train, y_train) # "fit" is just loading the context
pred = reg.predict(X_test) # one forward pass, a few seconds on CPU
I use the v2 weights on purpose. The default TabPFN-3.5 weights are non-commercial and want a browser login. The v2 weights are the Prior Labs License (Apache-2.0 plus attribution), so the whole stack stays genuinely open and runs headless. For an "open innovation" project that distinction is the point, not a footnote.
The features are the things that actually drive frost timing: latitude, elevation, the February and March mean temperatures, the coldest winter night, and an ENSO index for that winter. The target is the last-frost day-of-year. On a plain 8-core CPU it predicts in about 3 seconds, and I read the 10 to 90 percent quantiles for the range.
For a Chicago-like input it lands on May 20, range May 15 to 26. For Fargo it says June 19. Those match the real climate norms, which told me the model was learning the physics and not memorizing noise.
One honest note on the data. The 400-row dataset in the repo is grounded but synthetic: I generated it from documented last-frost norms for 20 real United States locations, so the relationships are real, but it is a teaching dataset, not a live weather feed. That is a feature, not a dodge. Point fit at your own weather-station CSV and the same model forecasts your actual backyard. The open stack is what makes that swap a one-line change instead of a support ticket.
The advice: Gemma 3, local via Ollama
The date is a number. A gardener wants a sentence. So a local Gemma 3 model, served by Ollama, turns the forecast plus the crop into guidance.
payload = {
"model": "gemma3:1b",
"prompt": f"{SYSTEM}\n\nLocation: {station}. Last frost: {date}. Plant: {crop}.",
"stream": False,
"options": {"temperature": 0.3, "num_predict": 160},
}
I started with gemma3:270m because it is tiny. It was too tiny: it ignored the frost date and chatted. gemma3:1b (about 815 MB) follows the instruction cleanly and still runs comfortably on CPU. One honest line in the design: the model is told the date, it never invents one. The number is always TabPFN's.
The fallback: when the model is not there
A tool that promises "works offline" has to survive the model being unreachable too. If Ollama is down, a deterministic tender-vs-hardy rule writes a correct tip from the same date. The app never shows a frightened spinner that never ends.
def advise(plant, forecast):
try:
return {"text": call_gemma(plant, forecast), "source": "gemma"}
except Exception:
return {"text": rule_based(plant, forecast), "source": "offline-fallback"}
The shell
A small FastAPI server wires the two models together and serves a single-page UI (Three.js for a quiet night-sky background, no build step). The server only ever talks to localhost. There is no outbound call anywhere in the request path once the weights are cached.
What the Data Actually Says
Once the model was fitting cleanly, I did the thing a forecast tool rarely does: I asked it what it had learned. I swept each feature across its real 10th-to-90th-percentile range and measured how many days the predicted last frost moved. Every number here is reproducible with python scripts/analyze.py.
The result surprised me.
| What changes | Realistic swing moves the last frost by |
|---|---|
| February mean temperature | 50 days |
| March mean temperature | 32 days |
| Coldest winter night | 27 days |
| Latitude | 24 days |
| Elevation | 12 days |
| El Nino / La Nina (ENSO) | 10 days |
Gardeners obsess over latitude. "I'm up north, so I plant late." But in this data a cold-versus-mild February swings your last frost more than twice as hard as how far north you are. The month most people ignore, the dead one before anything grows, is the strongest single tell. Latitude is a slow backdrop; February is the actual signal.
Two more things fell out of the sweep:
The El Nino signal is not shared equally. I expected it to shift everyone. It barely touches the cold north: at a Fargo-like station the La Nina to El Nino swing was about 0.1 days, basically nothing. At a Houston-like station it was 8 days. The climate oscillation you hear about on the news moves the mild south and leaves the frozen north alone.
Elevation is real but modest. At 40 degrees north, climbing from sea level to 1600 meters (think Denver) pushed the last frost about 13 days later. Real, worth knowing, but a quarter of February's pull.
None of this is on a frost-date website, because those sites look up a static average by ZIP code. They cannot tell you what moves your number. A model you can interrogate can. That is the difference between a lookup table and something that has actually learned the shape of the problem.
Why Does Open Innovation Matter?
I kept asking: would a closed, hosted model have made this better? Every time the answer was no.
Offline is the entire premise. The place you most need a frost date is the plot with no signal. A closed API cannot reach it. Open weights on your own disk work there. This is not a nice-to-have for FrostWise, it is the reason it exists.
Your location is yours. "Where do you garden" is personal data. With open weights there is no server to send it to, no account to create, nothing logged. A hosted model turns your garden into someone else's row in a database.
It costs nothing. Open weights mean zero per-request fees. A community garden can run it a thousand times and the bill is still zero. A metered API would make the same tool expensive at exactly the moment you want to share it.
You own the brain. You can read how TabPFN predicts, retrain it on your own weather-station records, and swap Gemma for any open-weight model Ollama can run. Nothing is locked to a vendor you cannot inspect. If a forecast looks wrong, it is my data and my model to fix, not a prompt I have to beg a black box to honor.
A closed API would have been faster to wire up for about an hour, and then wrong forever for the one person standing in a field with no signal.
My Agent Session
I built FrostWise with an AI coding agent, and I kept it honest the same way the app keeps its forecasts honest: the agent proposed, I verified every claim against a real run before it shipped.
The useful parts of that session, in order:
1. Research before code. The agent read the challenge rules, the official template, and two past winning posts, then wrote the "why open beats closed" argument from the prompt's own bullets instead of guessing.
2. A feasibility spike first. Before a line of product code, it proved both models actually run on a plain CPU box: TabPFN-v2 predicting a frost date in about 3 seconds, and gemma3:1b answering a planting question offline. Only then did we build.
3. Catching my own overclaim. During review the agent flagged that the dataset is synthetic and made me say so in this post, rather than let "matches real climate norms" imply a live feed. That note is in "How I Built It" now because the agent pushed back.
4. Real bugs, found by running it. A static-path mistake made the UI load blank; a weak gemma3:270m ignored the frost date. Both were caught by actually running the thing, not by reading the diff.
The through-line: the agent is fast, but nothing shipped until a real run backed it up. That is the same contract as the product. The model proposes, the evidence decides.
Did It Touch Grass?
I ran it for my friend's plot before she planted. FrostWise put her last frost in early May; she waited, set her tomatoes out the week after, and did not lose a single seedling to a late cold night. The screen part took about ten seconds. The rest of the afternoon she was in the dirt. That is the whole idea: the tool gets out of the way and sends you outside.
Prize Categories
- Best Use of Gemma. Gemma 3 runs locally via Ollama and writes every piece of planting advice. It is the whole language layer, offline, swappable, told the date so it cannot invent one.
- Best Use of TabPFN. TabPFN-v2 (open weights) is the forecaster. It predicts the last-frost day-of-year from climate features in one CPU pass, with a calibrated range, no training required. The date on screen is always its number.
---
Follow me for more on AWS architecture, DevOps, and AI Infrastructure:
Portfolio | LinkedIn | dev.to | YouTube | [Email](mailto:simplynadaf@gmail.com) | AWS Builder Center | X
21 reactions · 2 comments
Mentions
Is an LLM even the right tool for the job here? Prediction market historic data will mostly be tabular. Each outcome will have a number of discreet features associated with it, natural or engineered. Wouldn't a gradient boosted tree approach work better in this domain? xgboost, lightgbm etc. Or, if a neural network must be used, then one specifically tuned for tabular data work, like TabPFN, might be a better choice. Using an LLM here just feels like the wrong tool choice. [1] PriorLabs/tabpfn
I let an open model delete 1,242 of my saved articles. On purpose. I feel lighter. --- title: I let an open model delete 1,242 of my saved articles. On purpose. I feel lighter. published: true description: Unpile is a 100% local read-later triage agent. TabPFN decides which saved articles you will actually read, Gemma writes the digest, offline and free. tags: devchallenge, hf26challenge, ai, opensource --- This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady I had 1,247 articles saved "for later." This week I let a model on my laptop throw almost all of them away, and I have never felt lighter. Let me tell you why that was so hard, and why I would do it again. "Read later" is the most optimistic lie in software. Every tab I save is a tiny promise to a future version of me who does not exist, the one with a free Sunday and a cup of tea and nothing better to do. That version is never coming. So the pile just sits there, 1,247 promises deep, and taxes me a little guilt every single time I open a new tab. I was not keeping those articles. They were keeping me. The challenge this week, "Slow and Steady," asks for something that rewards laziness: channel your inner sloth, build the thing that does the work so you do not have to. So I built the one thing I was too afraid to do by hand. An agent that reads the whole pile overnight, on my own laptop, with the Wi-Fi off, learns which handful I will genuinely read, and then does the scary part for me: it deletes the rest. No cloud. No account. No cost. No more guilt. It is called Unpile. On the demo pile it reads 14 saved items, keeps the 5 worth my morning, flags 1 maybe, and silences 8, handing back 5.5 hours of reading time I was lying to myself about. Point it at a real 1,200-item backlog and it quietly clears years of guilt while you sleep. --- What I Built Unpile is a local triage agent for your read-later backlog. You point it at an export (Pocket, Instapaper, browser bookmarks, a CSV) and it does four things, all on your machine: 1. Learns your taste from your own history of what you actually read versus what rotted in the pile. 2. Decides every item: keep, skim, or drop, each with a calibrated probability that you will read it. 3. Writes a calm two-line morning digest of only the keepers. 4. Silences everything else, so you wake up to five good things instead of a wall of guilt. The effort it saves is the whole point of the challenge. You stop being the triage system. You stop scrolling a backlog deciding, item by item, "do I care about this?" The model does that boring, repetitive judgment call thousands of times and only taps you on the shoulder for the handful that survive. That is the sloth philosophy in one line: it does the work so you do not have to, and you get your attention back. Who gets to be lazier? Anyone with a doom-pile of unread tabs. Which, let us be honest, is every single person reading this. --- Demo Live, in your browser (no setup, real baked model output): simplynadaf.github.io Video walkthrough: watch on YouTube {% embed youtu.be %} The 60-second walkthrough goes end to end: the open-source repo, then the real pipeline running in a terminal (the reading history TabPFN learns from, the keep/skim/drop call with a reason for every item, the local Gemma digest, and the honest held-out scorecard), then the live site. Nothing is staged; the numbers on screen are the actual program output. !Unpile triaging a read-later pile: 5 kept, 1 maybe, 8 silenced, 5.5 hours reclaimed And here is the triaged pile itself: five keepers on the left (each with the reasons it survived and a one-line Gemma digest), one borderline maybe in the middle, and the eight it silenced on the right, the 11pm two-hour video essay, the "someday build a cabin" photo essay, the tabs-versus-spaces flamewar. !The keep, skim, and drop columns with probabilities and reasons The whole thing runs on a plain CPU. The numbers on the page are the real TabPFN-v2 and Gemma output, frozen into the static site so the demo cannot break in front of you; toggle any item and an in-browser mirror of the model re-decides live. --- Code {% github simplynadaf/unpile-read-later-triage %} --- How I Built It Two open-weight models, one job each. Neither is decoration; take either one out and the project stops working. TabPFN-v2 is the decision brain TabPFN (Prior Labs) is an open-weight tabular foundation model. You do not train it. You hand it your history as context and it predicts in a single forward pass. For Unpile, the history is a table of saved items with the signals you know the moment you save something (source, topic, estimated read time, how stale it is, how many times you reopened the tab, whether it is an actionable how-to, how buried it is) and one honest label: did you ever actually read it? Prior Labs specifically favors TabPFN used inside a wider prediction agent, not as a bare .predict() call. So Unpile wraps it in a real agent loop: # predict P(you read it) for the whole pile in ONE CPU forward pass probs = self._proba(items) for item, p in zip(items, probs): action = self._decide(p) # keep / skim / drop from a tunable keep budget reasons = self._reasons(item) # plain-language "why", so the call is auditable ... # keep the few, flag the maybes, silence the rot It predicts, decides an action, explains that action in plain language, and then reports honest held-out metrics on itself. That last part matters, and I will come back to it. I used TabPFN-v2 on purpose: it decides the whole pile in a single CPU forward pass, no GPU and no training run, which is exactly what lets Unpile run overnight on the laptop you already own. Gemma 3 is the writer Gemma 3 runs locally through Ollama and writes the morning digest. It is given the keepers and their probabilities and told to never invent an item. If Ollama is busy or the machine is offline, a deterministic fallback writes a correct digest anyway, so the summary always arrives: def write_digest(keepers): try: return gemma_via_ollama(keepers) # calm two-line morning note, local except Exception: return rule_based(keepers) # never blocks your morning The stack is FastAPI, a synthetic-but-documented dataset, a single-file no-build UI, and GitHub Pages for the live demo. All CPU, all local. --- Why Does Open Innovation Matter? Your reading list is a confession. It leaks your job, your health, your politics, the thing you are quietly trying to learn. That is exactly the data I refuse to send to someone else's server, and it is the reason this had to be open. - Your history never leaves the laptop. A closed API would need every row uploaded. TabPFN and Gemma run on-device, so it stays with you. - It works with the Wi-Fi off. Open weights mean the overnight triage does not depend on a connection, a login, or a vendor being awake. - It is free, at any scale. Triaging a 1,200-item backlog on a per-call API is a real bill. On open weights it is zero, so I can run it nightly and never think about cost. - It learns me, not the average. Retrain the decision on my own labels and it mirrors my taste. A closed, general model cannot be bent to one person's weird pile the way an open one can. A closed API could summarize an article. It could not become a private, offline, free thing that learns my specific reading habits and keeps running on hardware I already own, long after any free tier would have expired. That is the part only open makes possible, and it is the entire reason Unpile exists. --- The Lazy Payoff Here is what this actually bought me, and it was not time. It was permission to let go. I used to be the triage system. Every few days I would open that folder, feel the weight of 1,247 unread promises, scroll a bit, close it, and feel slightly worse than before. The backlog was not a to-do list. It was a slow-drip guilt machine I had built for myself, one hopeful tab at a time. What I could never do was the obvious thing: just delete them. Deleting felt like admitting I would never become the person who reads 1,247 articles. So I never did. The pile only grew. The model does not have that hang-up. It looked at my own history, decided which five were real, and threw the rest away without a flicker of guilt, because it does not have any. I did not read 1,242 items this week. I did not even look at them. And the folder that used to make me wince now makes me feel nothing at all, which, after years of that quiet tax, feels like a lot. Quantified in the only currency the challenge cares about: 8 of 14 items silenced with zero input from me, and 5.5 hours of reading time handed back, time I was lying to myself about anyway. Point it at a real 1,200-item backlog and it is clearing years of that guilt while I sleep. The sloth philosophy, literally: move slow, conserve energy, let the boring, frightening part happen without you. --- The Honest Take Here is the scorecard, measured on a held-out slice of 240 saved items the model never saw, because a number I cannot check is just a vibe. - Precision 0.60: when Unpile surfaces something, I actually read it about 60% of the time, against a 36% base rate in the raw pile. It nearly doubles the odds that the thing in front of me is worth it. - Lift 1.66x: the kept pile reads 1.66 times better than a random grab from the backlog. - Silenced 58%: it auto-archives well over half the pile with no input from me. That is the laziness, quantified. - Reclaimed 5.5 hours on the 14-item demo alone. Scale that to a real 1,200-item backlog and the model is doing days of triage you were never going to do yourself. And now the number I am putting right next to the good ones, on purpose: - Wrongly dropped 44%. At this setting, of the items I genuinely would have read, it also silenced about 44% of them. The most painful miss on the demo pile is "this week in AI (issue #214)" at 37% confidence: a fresh newsletter in a topic I follow, and it landed just under the keep line. It got silenced. On another morning I would have wanted it. I am not hiding that. Unpile is not magic; it trades recall for a calm morning. But the fix is a dial, not a lie: loosen one threshold (UNPILE_KEEP_T) and you recover more of those near-misses at the price of a slightly noisier digest. I would rather ship the honest trade-off, with the failure case named out loud, than a demo that pretends false negatives do not exist. --- Prize Categories - Best Use of TabPFN (featured): TabPFN-v2 is the decision brain, used as a real prediction agent (predict, decide, explain, measure) over a personal CSV, with honest held-out metrics, exactly the "prediction agent" pattern Prior Labs favors over a bare classifier. - Best Use of Gemma (featured): Gemma 3 runs locally via Ollama to write the morning digest, grounded strictly on the model's own output, with a deterministic offline fallback so it never hard-fails. Built new for this challenge (Oct 19 to 25). It reuses my own local-AI patterns from earlier weeks, re-applied to a new problem, dataset, agent loop, and UI, disclosed in the README per the credit rule. --- Thanks for reading all the way down. You just did something your backlog never let you do: you finished. Now go let a model read the rest for you.
TabPFN 3.5 — модель работы с табличными данными, умеющая в Фурье-препроцессинг, тестируем по SDD (OpenSpec + OpenCode) Наконец-то приехала фундаментальная модель, заточенная под работу с табличными данными и уже в базе умеющая препроцессить сырые данные. И у меня дошли руки ее потестировать. Технический отчёт: arxiv.org Обзор отчёта: arxiviq.substack.com Код (pip-пакет tabpfn): PriorLabs/TabPFN Веса модели: huggingface.co А у меня как раз такие данные, которые идеально подходят для теста этой модели: записи отсчетов измерений напряжения с умной розетки в разных сценариях энергопотребления. Нюанс этих данных в том, что их, конечно, можно интепретировать как временные ряды, но гораздо эффективнее извлекать из них FFT-спектры и работать уже с частотным представлением. В посте двухгодовалой давностилучшие результаты показал ансамбль катбустов в составе фреймворка Light Auto ML - именено после предварительного процессинга табличных данных и переходом от временного представления (Time Series) к частотному через быстрое преобразование Фурье (FFT). Увы, руки уже не столько мои, сколько кодингового агента, но на этот раз я взял на вооружение SDD (Specification-Driven Development) в реализации OpenSpec. Из прошедших через мои руки бесплатных и условно-бесплатных альтернатив самому популярному агенту на букву "К" я остановился на OpenCode как самой продвинутой на текущий момент (из тех, что успел "пощупать"). Сразу оговорюсь - многое зависит от того, какая конкретно модель используется внутри OpenCode, буквально вчера я решал другую задачу с помощью MiniMax 3.1-Flash, и пришлось править две ошибки, а сегодня GLM-5.3-Flash меня приятно удивила быстротой, точностью выполнения моих инструкций - и отсутствием ошибок (кроме одного нюанса, который был обнаружен экспериментальным путем). Ну и, конечно, следование подходу SDD. Результат будет хз, если не было... спецификаций Сам подход, безусловно, не нов. Но он предоставляет мощную подпорку для работы белковых разработчиков с искусственными нейронными сетями: во-первых, он заставляет четко формулировать задачу. Кажется очевидным, но давайте будем честны в ответе на вопрос - а мы сами-то всегда ли четко артикулируем то, над чем работаем? Для тех, кто не застал СССР, хочу напомнить старый советский анекдот, отражавший дефицит суперкомпьютеров в Советском Союзе: Американский физик спрашивает у советского: "Как вам удается достигать таких высоких результатов в науке, ведь ваши компьютеры сильно отстают от наших?" На что тот отвечает: "Все просто: вы садитесь за компьютер и думаете над каждым его ответом, а мы сначала думаем, а потом уже садимся за компьютер". Тут тоже самое. Сначала подумай, какую задачу ты хочешь решить. Какие есть ограничения. Какие ожидания. И только после этого запускай команду /opsx-proposal или /openspec-proposal. Provided arguments: ## Цель: протестировать новую модель TabPFN-3.5 на данных о сценариях потребления энергии пользователями. Задача: создать .ipynb ноутбук Ресурсное ограничение: .ipynb ноутбук должен работать в Google Colab Описание TabPFN-3.5: Информацию о модели можно взять из статьи: arxiv.org и ревью к ней arxiviq.substack.com Код можно взять в репозитории PriorLabs/TabPFN А саму модель из huggingface.co Я не вижу размера модели на HF, поэтому первый же вопрос: требуется ли GPU или можно запустить на CPU? Второй вопрос: если все-таки требуется GPU, влезет ли она в T4, доступный в Google Colab? Данные для проверки Пример загрузки данных из монтируемого Google Drive описан в ноутбуке TimesFM3_DeepSeek.ipynb - он лежит в папке проекта Если требуется предобработка данных - смотри на структуру данных в этом ноутбуке. Дополнительно: избегай установки лишний пакетов - минимизируй зависимости. После генерации ноутбука проверь на наличие лишнего кода, удаляй неиспользумый код и импорты Каждую ячейку снабжай подробным комментарием: что здесь проиходит и зачем это нужно. Также не забывай снабжать описания классов docstring и комментариями. Разбивай секции markdown-ячейками. После того как агент отработает, стоит проверить артефакты генерации спефикации в папке /openspec/changes - ищем там proposal.md и tasks.md. Второй аспект полезности SDD: когда у агента переполняется окно внимани, он сжимает (суммаризирует) текущую сессию - и перезапукается. При перезапуске он подгражует себе Guardrails и прочие настройки системного промта (при желании их можно найти и подшаманить), а также саммари контекста сессии и спецификации. Если вы используете локальные модели с небольшим окном контекста, то перезапускаться агент будет часто. Поэтому чем давать комментарии по ходу исполнения, которые будут как-то суммаризироваться, лучше сразу записать их в спецификацию. У нас почти все получилось. Но всплыл нюанс: TabPFNLicenseError: TabPFN requires a one-time license acceptance to download model weights for local inference, but no interactive terminal is available. Агент утверждает, что этого не было в документации: Interesting: the README/HF card I fetched didn't mention this — but the FAQ had "How do I use TabPFN without an internet connection?" and "How do I get access to TabPFN-2.5/3/3.5?" questions. The error message explains the flow: register at ux.priorlabs.ai, accept license, copy API key, set TABPFN_TOKEN env var before fit(). Options: 1. User accepts license once at ux.priorlabs.ai, gets API key, sets os.environ["TABPFN_TOKEN"] in a Colab cell before evaluation. I should update the notebook to handle this: add a config cell (early) where user pastes their API key or it checks TABPFN_TOKEN, with clear Russian explanation, without breaking the "Run All" neutral flow. 2. Alternative: check if HF token works — the error mentions try_browser_login(gui_url, hf_repo_id=...). In old tabpfn versions, downloading from HF worked anonymously (the model card earlier versions had no gating). Apparently for 3.5 the package introduced license-gating with API keys. Но, на самом деле, агент не совсем прав - веса можно скачать напрямую с HuggingFace, они там реально выложены и их можно скачать без авторизации. Но для этого надо влезть в импортируемый пакет tabpfn и переделать загрузку весов. Агент пошел по первому пути, предложив зарегаться на сайте Prior Labs (поставщиков пакета), получить API Key и добавить его в секреты Colab-ноутбука. Аплодирую Prior Labs - молодцы, грамотно придумали способ сбора статистики загрузок, независимый от HF. Ну а для себя - отмечу еще идин пункт в будущих спефикациях. Ну, собственно, все. Модель отработала: Матрица ошибок классификации И модели удалось превзойти по макроусредненной F-мере baseline: ансамбль катбустов (с которого все начиналось) - пусть и немного, всего на 1 процент. Пожалуй, запишу себе модель в список проверенных инструментов для классификации табличных данных. Код опубликован в репозитории Archelephant/TabPFN_w_OpenSpec З.Ы. А вот знаете, что я забыл добавить в спецификацию перед пушем в Github? Можете накидать мне в комментариях...
I Built an Open-Weight AI That Prices Etsy Shops, On Your Laptop --- title: "I Built an Open-Weight AI That Prices Etsy Shops, On Your Laptop" published: true tags: devchallenge, hf26challenge, tabpfn, opensource --- This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle !PricePilot: price it right, then watch it sell My friend runs a tiny candle shop on Etsy. Forty-odd listings, a day job, and a pricing strategy she described to me, without a trace of irony, as "vibes." She is not wrong to struggle. There is no sticker price for a hand-poured soy candle. The right number depends on the scent, the size, the wax, how long it took, the season, how many photos she shot, how her shop is rated. A dozen little things that interact. Price it $4 too high and it sits until the wax degrades. Price it $4 too low and she is paying Etsy fees to work for free. She has lost real money both ways. The tools that promise to fix this are closed SaaS products: a monthly fee, and an upload of her entire sales history to someone else's server so they can rent her a number back. For a shop that clears maybe $300 a month, that is a bad trade twice over. There is the cost. And there is handing the one thing that is actually hers (what sells, at what margin) to a stranger's cloud. So I built her PricePilot: a pricing copilot that runs entirely on her laptop. It predicts what an item will sell for from sold-listings data, then writes the listing. No account, no API bill, nothing uploaded anywhere. --- What I Built PricePilot turns one short form into three things a seller can act on immediately: 1. A price with an honest range. Not a single false-precise number but a predicted sell price and the 10–90% band around it, plus a measured error so you know how much to trust it. 2. The levers that raise it. It doesn't just score the listing; it tells her *what to change and by how much*: "offer personalization, about +$5", "list in the Q4 season, about +$8", "use premium materials, about +$12", ranked by dollar impact. 3. A ready-to-paste listing. Title, description, and eight search tags, written to match the predicted price. Who would pay for it: independent Etsy, eBay, and marketplace sellers. The exact "side hustle" person this week is about. The thing it fixes (what do I charge?) is the thing that most directly decides whether the hustle makes money. --- Demo 🔗 Live demo (fully interactive): simplynadaf.github.io 🎥 Video walkthrough: watch on YouTube > The hosted demo is interactive end to end: every field is editable and the price updates instantly, powered by an in-browser estimate that mirrors the model. For the actual TabPFN-v2 prediction with Gemma 3 writing the listing, clone the repo and python run.py, fully offline. That is the whole point of PricePilot. Describe an item the way you'd list it (category, materials, size, hours to make, condition, photos, season) and PricePilot prices it and drafts the listing in one shot. !PricePilot result: a predicted price with its 10–90% range, the ranked what-if levers, and a listing with title, description, and tags --- Code {% github simplynadaf/pricepilot %} --- How I Built It PricePilot is two open-weight models doing one honest job each, locally. !How it works: you describe the item, TabPFN-v2 predicts the price, Gemma writes the listing The price: TabPFN-v2 as a prediction agent Pricing is a textbook small-data tabular problem (a few hundred past sold listings, ten features, one continuous target), which is exactly what TabPFN-v2, Prior Labs' open-weight tabular foundation model, is built for. It predicts in a single CPU forward pass with no per-dataset training. But Prior Labs explicitly favors TabPFN used inside a wider prediction agent, not as a one-shot regressor, so that's what I built. PricePilot: - predicts the sell price with a calibrated 10–90% range from TabPFN's output quantiles, - then runs a small what-if loop: it re-queries TabPFN under single-feature changes a seller actually controls (more photos, personalization, Q4 timing, better condition, premium materials) and ranks them by the dollar delta, all in one batched forward pass so it stays fast on CPU, - and reports a held-out mean absolute error so every number is measured, not asserted. On the sample dataset, TabPFN predicts held-out sold prices with an MAE of about $2.90 on items averaging ~$54. That is roughly 5% error, with zero training time. The honesty number is the whole point: she can see how much to trust it. # the prediction agent, simplified: predict, then re-query to explain the number mean, low, high = self._predict_one(feats) # price + 10-90% range preds = self._predict_rows(whatif_rows) # ONE batched pass for every lever levers = sorted( (WhatIf(label, round(p - mean, 2)) for label, p in zip(labels, preds)), key=lambda w: w.delta, reverse=True, ) The listing: Gemma 3, grounded on the number A local Gemma 3 model (open-weight, served by Ollama) turns the item and that exact predicted price into a title, description, and tags. It is told the price and told never to invent a different one. The number is always TabPFN's. Gemma just writes the copy around it. The safety net If Ollama isn't running, a deterministic template writes a correct listing from the same price, so she is never staring at a spinner. The whole stack (FastAPI, a no-build premium front end, both models) runs on localhost. I verified the offline path by pointing the Ollama host at a dead port and confirming the listing still came back. --- Why Does Open Innovation Matter? This is the part that made the project worth building, and every point is something a closed API would have taken away: - Her sales data stays hers. What sells, at what margin, is her entire edge. PricePilot never uploads it. A closed pricing tool would turn her shop's history into its training data. - $0 per listing. Open weights mean no per-call fee. She can reprice her whole shop every week and the bill is nothing. A subscription would eat the margin the tool is supposed to protect. - It can learn her niche. She can drop in her own exported Etsy sales CSV and the model fits her corner of the market (soy candles in her price band) where a general API trained on "everything" is mediocre. The open approach is what lets the long tail have a model that fits it. - No lock-in. The listing writer points at any open-weight model Ollama runs; the predictor can be retrained. She owns the stack, not a line on someone's pricing page. A frost date, a race time, a candle price: the pattern that keeps winning this Hacktoberfest is the same. A small, open model, running where your data already lives, beats a big closed one you have to pay and trust. --- My Agent Session I built PricePilot with an AI coding agent, and the honest story of the build is that the two hard problems were both about trust in the numbers, not wiring. First, TabPFN on CPU was slow enough to feel broken until I batched every what-if scenario into a single forward pass (the per-request time dropped from minutes to seconds). Second, I had to stop the language model from ever emitting its own price, so the agent and I settled on a rule the whole design now rests on: Gemma is told the number and never produces one. The repo's commit history tracks that path from a bare TabPFN spike to the batched prediction agent. --- My First User I built PricePilot for a real person: a friend who runs a small candle shop on Etsy and genuinely prices by "vibes." I have not sat her down with the finished build yet (that is my next step, and I will update this post with what she says), so I will not invent a reaction here. What I can say honestly is why I think she, and sellers like her, would pay: - The pain is the money. Pricing is the single decision that most directly sets whether a handmade shop earns or loses on each sale. A tool that gives a defensible number, with a range and a measured error, targets the exact spot where a side hustle leaks money. - The alternative already costs money. Sellers pay $10–30/month for closed pricing SaaS that also wants their sales history uploaded. PricePilot does the same job for $0 and keeps the data on their laptop. "Same outcome, free, private" is an easy yes. - It answers a question they ask constantly. "What do I charge, and what do I write?" is a daily question for an active seller. PricePilot answers both in one shot. My honest take: I would not charge for the current build, because the whole point is that it runs free on the seller's own machine. The thing a seller would actually pay for is the time and the second-guessing it removes, and that is what I will test with her next. --- Prize Categories - Best Use of TabPFN: TabPFN-v2 is the core: it predicts the price, provides the calibrated range, and is wrapped in a what-if prediction agent that re-queries the model to explain which levers move the number. Accuracy is reported as a held-out MAE (~$2.90), so the claim is measured, not asserted. --- *Built with open weights, on a laptop, for a friend who prices by vibes. Made with 🤍 by Sarvar.*
Turnaround: an open-source hiking buddy that knows when you should turn back, and tells someone if you don't come home This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass Most hiking trouble isn't dramatic. Nobody falls off a cliff. Someone simply keeps going a little too long because the summit is "just around the corner", the sun sets earlier than they thought, and the only person who knows where they went is themselves. Two things would fix most of that: 1. Knowing, before you leave, the time you should turn around, based on how fast you actually walk rather than a sign at the trailhead. 2. Someone you trust finding out automatically if you don't come back, without you having to remember to tell them. So I built Turnaround. You spend about two minutes with it before a hike, then put your phone in your pocket. What I Built Turnaround is a hiking companion that runs entirely on your own laptop. Before a hike it gives you three times: - Turn around by: not at the top or the far end by this time? Head back. - Back by: 9 in 10 hikes like yours finish before this. - Sunset margin: how much daylight you have to spare. Then it does four things: - Predicts how long you will take, as a range rather than a single guess. An open tabular foundation model (TabPFN) learns from 7,186 real recorded hikes and adjusts to your pace after every hike you finish. - Briefs you out loud. Gemma 4, running locally, turns the numbers into a short spoken briefing that sounds like a friend who hikes. It's saved to your phone before you leave, so it plays with no signal. - Watches. When you tap Start, a durable safety timer begins waiting for your check-in. - Tells someone. If you're well past your back-by time and still haven't checked in, your emergency contact gets an email with your plan, your route and a map link to where you set off. If you then check in late, they get a second email saying you're safe. No GPX file? You just enter the three numbers every trail page lists (distance, elevation gain and trailhead), and Turnaround plans from those. Who it's for: anyone who hikes alone or is new to it, and anyone with a parent, partner or friend who worries when they head out. How it gets you off the screen: the screen part is the beginning and the end of the trip. Plan, listen, pocket the phone, walk. The next time you look at it is to tap Hike complete. How it works !How it works: plan, go, check in Demo {% youtube eOzc_RNBzMk %} The video walks through the whole flow: planning a hike, the spoken briefing, starting the trip and the safety timer, and checking in. Turnaround runs on my laptop, by design (more on that below), so there's no public link. The repo has one-command-per-terminal setup if you want to run it yourself. Code {% github CodeNeuron58/Turnaround no-readme %} MIT-licensed. CI runs typechecks, the app build and two unit-test suites on every push. Everything I claim below has a file in the repo backing it. How I Built It Everything runs on one laptop: - Phone or browser → the app (React + Vite), reached over Wi-Fi or Tailscale - App → the prediction service (FastAPI + TabPFN + SQLite) - Prediction service → Gemma 4 (via Ollama) for the briefing, Kokoro for the voice, and the Temporal server to arm the timer and send check-ins - Temporal worker → the alert and all-clear emails to your contact The only things that leave it are an anonymous weather lookup (coordinates only) and, if you're overdue, the alert email. 1. Predicting your hike time: TabPFN The classic hiking-time rule is Naismith's rule: roughly 12 minutes per kilometre plus 1 minute per 10 m of climbing. It's on half the trail signs in the world, and it gives the same answer for everyone. I wanted a range, and I wanted it to fit the person. TabPFN is an open tabular foundation model: you give it a table of examples and it predicts new rows in context, with no training loop. Crucially for a safety tool, it returns a full predictive distribution rather than one number. The data is 7,186 GPS-recorded hikes from hikr.org (a public Kaggle dataset, CC0). The features are distance, climb, descent, highest point and the SAC difficulty grade (T1–T6). I held out 1,438 hikes the model never saw and compared it with Naismith: | On 1,438 unseen hikes | Naismith's rule | TabPFN v3.5 | |---|---|---| | Average error | 44.1 min | 34.8 min | | RMSE | 69.1 min | 54.5 min | | Real times inside the predicted 90% band | — | 89.5% | | Hikers back before the "back by" time (P90) | — | 90.4% | The last row is the one I care about most. A safety tool has to be honest about its uncertainty, not just accurate on average. When Turnaround says "9 in 10 hikes like this are done by 4:40", that turns out to be true for 90.4% of hikes. Average error being 21% lower is a nice bonus. On a laptop CPU I serve TabPFN v2 by default. It's about 3x faster with nearly identical calibration (89.7%). The v3.5 checkpoint is one environment variable away. How the prediction becomes decisions: - Back by = the 90th percentile + your planned breaks. - Turn around by = the share of that time you should spend heading out, assuming you retrace your steps. Climbing happens on the way out, so steep routes front-load it (Naismith's split, clamped between 50% and 70%). - Alert = the 95th percentile + breaks + 30 minutes of grace. I deliberately didn't make it the back-by time: your contact should only be emailed when you're genuinely late, not five minutes slow. Learning your pace. The crowd isn't you. Every hike you finish compares your actual moving time with the model's median for the same route, and the ratios combine into a personal pace factor. It's shrunk toward 1.0 on purpose, so one bad day can't swing the safety timer. A hike that was 40% slower than predicted moves your next estimate up about 12%, not 40%. Hikes where you tapped I turned back early don't count, because a turned-back time says nothing fair about the whole route. All of these rules are in a small, unit-tested module. 2. A promise that survives a crash: Temporal The scariest bug a safety app can have is a timer that silently dies. If the alert depends on a Node process staying alive for six hours on a laptop, it's not a safety feature, it's a hope. So the safety timer is a Temporal workflow. One tripWorkflow per hike races a check-in signal against a durable timer set to the alert moment. Sending the email is an activity with retries. A late check-in after the alert triggers the all-clear. I run Temporal's free local dev server with an on-disk database, so timers survive a restart of the server itself, not just the worker. Then I tried to break it. Each scenario has its workflow history or logs committed in docs/evidence/: | # | What I did | What happened | |---|---|---| | 1 | Checked in on time | Timer closed, nobody emailed | | 2 | Missed the check-in while the mail server failed | Activity retried; alert went out on attempt 2 | | 3 | Killed the worker mid-trip, restarted it 25 s later | Alert still fired exactly on the deadline: 90.5 s after start, despite the worker being dead from second 20 to 45 | | 4 | Drill: missed check-in, then a late check-in | Alert on the deadline, then an all-clear | | 5 | Killed the Temporal server mid-trip | Timer survived on disk; a check-in sent during the outage reported the failure honestly and landed when re-sent | Scenario 3 is the whole reason Temporal is here. The promise didn't notice the outage. This is what your contact actually receives. Both emails below were delivered to my own phone through Brevo, using the same templates and code path the worker uses (sent with the preview command, which is why they're marked [PREVIEW]): !The alert email and the all-clear email, as they arrived on my phone The alert says who, which route, when they set off and when they should have been back, with a one-tap map link to the starting point. The all-clear tells your contact they can stand down. Nobody has to decode a log file at 4 a.m. The app is equally honest when something is wrong. If the timer fails to arm, the trail screen shows a red "safety timer NOT armed" banner with a retry button rather than pretending you're covered. If you check in with no signal, the check-in is saved on the phone and sent the moment it can reach the laptop, and re-sending is idempotent, so a flaky connection can't double anything. 3. A briefing that sounds like a friend: Gemma 4 + Kokoro Numbers on a screen are easy to ignore. A voice in your ear saying "If you're not at the top by 1:40, turn around. The view will still be there next weekend" is not. Gemma 4 (E4B) runs locally through Ollama's OpenAI-compatible endpoint. The service hands it the trip's facts (distance, climb, turn-around and back-by times, sunset, rain chance, trailhead) and asks for 4 to 6 short sentences "like a friend who hikes, not a robot", always including the turn-around rule. Kokoro, an open 82M-parameter text-to-speech model, reads it aloud on the same machine. The text and audio are generated once, stored, and saved to your phone while you still have signal. Gemma is the voice, never the source of truth: every number it speaks comes from the prediction service, and if the sunset time is unknown, the prompt tells it to say so rather than invent one. The app React + Vite, three screens: Plan, On trail and Summary. Your phone reaches the laptop over the same Wi-Fi, or over Tailscale on mobile data, so nothing is exposed to the public internet. Weather and sunset come from Open-Meteo, with no API key and coordinates only. Alert emails go through a free Brevo account, and every email is also written to a local outbox as a record. Why Does Open Innovation Matter? Think about what a hiking plan reveals: where you'll be, that you'll be alone, and until when. I don't think that belongs on someone else's server, and with open models it doesn't have to. - Your location stays on your machine. Gemma 4, TabPFN and Kokoro all run on my laptop. A closed AI API would see every trailhead I start from and every hour I'm out alone. - It costs nothing to run. No subscription, no per-request bill, no key that expires mid-hike. A hiking club could host it for its members on one old laptop or a Raspberry Pi-class box. - The uncertainty is mine to inspect. With TabPFN's weights and a public dataset, I could measure calibration on 1,438 unseen hikes myself. A closed "estimated time" API gives you a number and asks for trust. For a feature that decides when your family gets an alarming email, I wanted the evidence. - Everything is swappable. The checkpoint is one environment variable (v2 for speed, v3.5 for accuracy), Gemma could be any model behind an OpenAI-compatible endpoint, and Piper is a drop-in fallback for Kokoro. Nothing in the stack can be deprecated out from under it. - The data is a commons. The model learns from thousands of hikers who shared their tracks publicly, and gives each new hiker something back. Where open was genuinely better for me, not just cheaper: calibration. I needed to know that "back by" means 90%, and I could only know that because I could run the model myself on data I could see. Honest limits. So far I've tested Turnaround at home, with sample routes and missed-check-in drills; taking it on a real trail is next. It's a prototype, not a replacement for telling someone your plan or carrying a satellite messenger in real backcountry. The laptop has to stay awake and online for the alert to send. The model knows hikr.org's mostly Alpine hikers best, and the pace factor exists precisely because you are not them. Prize Categories - Best Use of TabPFN: TabPFN predicts each hike's moving time as a calibrated distribution. Its P90 becomes the back-by time, its P95 sets when your contact is alerted, and its median feeds your personal pace factor. On 1,438 unseen hikes it beat Naismith's rule (34.8 vs 44.1 min average error) with 90.4% of hikers back before P90. - Best Use of Temporal: the safety timer is a durable Temporal workflow that races a check-in signal against the alert deadline, retries the alert email, and sends an all-clear on a late check-in. Tested by killing the worker and the Temporal server mid-trip, with evidence in the repo. - Best Use of Gemma: Gemma 4 runs locally via Ollama and turns each trip's numbers into a short spoken briefing (voiced by Kokoro) that's saved to your phone before you lose signal. --- Thanks for reading. If you hike alone, I'd love to hear what would make you actually use something like this, and what time you'd want to be told to turn around. 🥾
Frostline: what to plant this week, from your local frost dates Most garden advice is a fixed calendar. But the right week to sow a carrot in Portland is not the right week in Minneapolis. A calendar does not know that. Your frost dates do. Frostline asks for your location and tells you exactly what to sow this week, from your own last-spring and first-fall frost dates. The screen is the shortest part. Read the plan, close the laptop, go plant. - Live demo: frostline-lime.vercel.app - Code: zkasuran/frostline What it does Type a US city or tap "use my location". Frostline shows your two frost dates, then a sow-this-week list drawn from 29 common vegetables and herbs, each with a plain reason like "sow kale now, it takes a light frost and keeps going into the cold". It reads at a glance and needs no sign-in. Open-source AI is the core, not the garnish Two open models do the real work. Frost dates come from TabPFN, an open tabular foundation model from Prior Labs. I trained it offline on 6,784 NOAA weather stations to predict the last-spring and first-fall 32F frost dates from latitude, longitude and elevation. On 1,357 stations held out of training it is accurate to 6.9 days for the last spring frost and 9.7 days for the first fall frost, which beats a nearest-station baseline (8.7 and 10.8 days) on both. The write-up comes from Gemma, Google's open-weight model. The live site writes it with Gemma 3 served openly through OpenRouter, with the built-in narrator as the instant fallback so the page never blanks. The result is cached per place and day, so a reload is immediate. Why open matters here, concretely: - It runs cheap. Gemma 3 costs a fraction of a cent per plan, so a free gardening tool stays free. - Your location stays yours. Your coordinates go to the Frostline server only, where they are matched against the baked grid. They are never forwarded to a model vendor and nothing is stored. When Gemma writes the plan it sees a coarse label (your city name or just "your location") and the frost dates, never your exact position. - You can swap the model. Retrain the frost model on your own stations or point the advice at any open model with one environment variable. - It can run offline. Open weights mean the whole pipeline can run on a laptop with no internet, which is the point of a tool you use outside. How it works TabPFN needs PyTorch, so it never runs on a request. I bake it once, offline, into a 0.25 degree US grid of 16,353 points and ship that as a small static file. At request time a tiny lookup interpolates your location against the grid, a deterministic planner turns your frost dates and today into the sow-this-week list, then Gemma writes it up. No model sits in the hot path for the frost dates, so the plan is instant and the site cannot blank. What is real and what is simulated I will not dress this up: - Frost dates are real TabPFN predictions from NOAA 1991-2020 normals. The error above is measured on held-out stations. - The plan is a real deterministic function of your frost dates and today. - The advice prose is written live by Gemma 3, with the built-in planner as the instant fallback. The app labels which one wrote it. - Frost-free places like Miami and Key West are labelled from the measured NOAA freeze probability of the nearest stations, not from a guessed date, so the app never pretends a frost-free spot has a hard frost. The Reports page shows all of it. The two partner categories - Best Use of TabPFN: frost-date prediction is a clean small-tabular regression, exactly what TabPFN is for. It beats the obvious baseline. The accuracy is published in the app and reproducible from bake/train_tabpfn.py. - Best Use of Gemma: Gemma writes every plan on the live site, grounded on a strict facts-only prompt so it never invents a date or a crop, with a deterministic fallback so the product is never at the mercy of the model. Built to be attacked One command gates the whole thing (./verify.sh): strict types, zero-warning lint, tests, a production build and a clean dependency audit. The site ships a strict nonce Content-Security-Policy, security headers, validated inputs and a route error boundary. The threat model is in the repo. Try it Open frostline-lime.vercel.app, type your city and see what you could put in the ground this week. Then go outside. --- AI assistance (Claude) was used to build Frostline. The design, the model choices and the licence decision are mine. Every number here is measured against the code and the live site so you can check it yourself.
I built an offline AI that knows your last frost date, no internet, no API --- title: I built an offline AI that knows your last frost date, no internet, no API published: true description: An open-weight tabular model forecasts your last spring frost and a local Gemma writes the planting advice. Fully offline, no account, $0 to run. tags: devchallenge, hf26challenge, ai, opensource cover_image: canonical_url: --- This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass The most useful number in a vegetable garden is the last spring frost date. Get it wrong by a week and one cold night turns your tomato seedlings to mush. Every tool that gives you that number has the same flaw. It lives on a server. You look it up on your phone, standing in the one corner of the allotment that gets a bar of signal, hoping the page loads before the rain starts. So I built FrostWise: it predicts your last frost and tells you what to plant, and it does the whole thing on your laptop with the Wi-Fi off. Two open-weight models, no API key, no account, nothing leaves the machine. I built it for a specific person: my friend who keeps a plot at a community garden on a hill where the signal drops to nothing. Every spring she texts me "is it safe to plant yet" because she cannot load a frost-date site from the plot itself. FrostWise is the answer she can keep on her own phone and open with no bars. What I Built FrostWise answers one question honestly: when does the cold let go where you are, and what should you do about it. You pick a location (or type your own climate numbers), choose a crop, and it returns three things: - A date. Your predicted last spring frost, with an honest range, not a fake single-day promise. - The advice. Plain language for your exact crop. Wait until after the frost for tender things like tomato and basil. Sow a few weeks early for hardy things like peas and kale. - A reason to trust it. The number comes from a model you can inspect and retrain, and the range tells you the risk. It gets people off the screen in the most literal way. The screen is the ten seconds you spend before you walk outside and put a seed in the ground. The whole point is to make that part short. Who it is for: anyone with a patch of soil and a spotty signal. Community plots, hillside allotments, a herb bed at a trail-head cabin. The places where a cloud API is useless are exactly where people garden. !FrostWise homepage: the headline Know when the frost lets go over a soft midnight-galaxy starfield, with Plan my garden and How it works buttons Demo Try it now: d2damz5gbd2rbh.cloudfront.net That hosted link is a static site (S3 plus CloudFront, near zero cost) that serves real, pre-computed TabPFN-v2 and Gemma results for the preset cities, so you can click through actual model output. The live models themselves run on your own machine. For custom climate input, fully offline, clone the repo and run python run.py. Here is the full flow across three very different climates: Miami (effectively frost-free), Chicago (a real May frost), and Fargo (frost that lingers into summer). Same code, three honest answers. Here is what one answer looks like: a predicted last frost, the honest range around it, and planting advice written locally by Gemma for the exact crop. !FrostWise result for Chicago: a predicted last spring frost of May 20, likely between May 15 and May 26, with an amber advice card for tomato written locally by Gemma The frost date animates in, then a local Gemma model writes the planting advice live. Nothing in that video calls out to the internet. Code {% embed simplynadaf/frostwise %} Clone it, python run.py, and it is on localhost:8077. The first forecast caches the model weights once; after that you can pull the network cable and it still works. How I Built It The whole thing is two open-weight models doing one honest job each, locally. !FrostWise architecture: the browser sends a location and crop to a local server; TabPFN-v2 forecasts the last-frost day on CPU; Gemma 3 in local Ollama turns that date into advice; a deterministic rule covers the offline fallback; nothing leaves the machine The forecast: TabPFN-v2 TabPFN is a tabular foundation model from Prior Labs. It is the strange and wonderful part. Instead of training a model on my frost data, I hand it the data as context and it predicts in a single forward pass. No training loop, no hyperparameter search, no GPU. from tabpfn import TabPFNRegressor from tabpfn.constants import ModelVersion reg = TabPFNRegressor.create_default_for_version(ModelVersion.V2, device="cpu") reg.fit(X_train, y_train) # "fit" is just loading the context pred = reg.predict(X_test) # one forward pass, a few seconds on CPU I use the v2 weights on purpose. The default TabPFN-3.5 weights are non-commercial and want a browser login. The v2 weights are the Prior Labs License (Apache-2.0 plus attribution), so the whole stack stays genuinely open and runs headless. For an "open innovation" project that distinction is the point, not a footnote. The features are the things that actually drive frost timing: latitude, elevation, the February and March mean temperatures, the coldest winter night, and an ENSO index for that winter. The target is the last-frost day-of-year. On a plain 8-core CPU it predicts in about 3 seconds, and I read the 10 to 90 percent quantiles for the range. For a Chicago-like input it lands on May 20, range May 15 to 26. For Fargo it says June 19. Those match the real climate norms, which told me the model was learning the physics and not memorizing noise. One honest note on the data. The 400-row dataset in the repo is grounded but synthetic: I generated it from documented last-frost norms for 20 real United States locations, so the relationships are real, but it is a teaching dataset, not a live weather feed. That is a feature, not a dodge. Point fit at your own weather-station CSV and the same model forecasts your actual backyard. The open stack is what makes that swap a one-line change instead of a support ticket. The advice: Gemma 3, local via Ollama The date is a number. A gardener wants a sentence. So a local Gemma 3 model, served by Ollama, turns the forecast plus the crop into guidance. payload = { "model": "gemma3:1b", "prompt": f"{SYSTEM}\n\nLocation: {station}. Last frost: {date}. Plant: {crop}.", "stream": False, "options": {"temperature": 0.3, "num_predict": 160}, } I started with gemma3:270m because it is tiny. It was too tiny: it ignored the frost date and chatted. gemma3:1b (about 815 MB) follows the instruction cleanly and still runs comfortably on CPU. One honest line in the design: the model is told the date, it never invents one. The number is always TabPFN's. The fallback: when the model is not there A tool that promises "works offline" has to survive the model being unreachable too. If Ollama is down, a deterministic tender-vs-hardy rule writes a correct tip from the same date. The app never shows a frightened spinner that never ends. def advise(plant, forecast): try: return {"text": call_gemma(plant, forecast), "source": "gemma"} except Exception: return {"text": rule_based(plant, forecast), "source": "offline-fallback"} The shell A small FastAPI server wires the two models together and serves a single-page UI (Three.js for a quiet night-sky background, no build step). The server only ever talks to localhost. There is no outbound call anywhere in the request path once the weights are cached. What the Data Actually Says Once the model was fitting cleanly, I did the thing a forecast tool rarely does: I asked it what it had learned. I swept each feature across its real 10th-to-90th-percentile range and measured how many days the predicted last frost moved. Every number here is reproducible with python scripts/analyze.py. The result surprised me. | What changes | Realistic swing moves the last frost by | |---|---| | February mean temperature | 50 days | | March mean temperature | 32 days | | Coldest winter night | 27 days | | Latitude | 24 days | | Elevation | 12 days | | El Nino / La Nina (ENSO) | 10 days | Gardeners obsess over latitude. "I'm up north, so I plant late." But in this data a cold-versus-mild February swings your last frost more than twice as hard as how far north you are. The month most people ignore, the dead one before anything grows, is the strongest single tell. Latitude is a slow backdrop; February is the actual signal. Two more things fell out of the sweep: The El Nino signal is not shared equally. I expected it to shift everyone. It barely touches the cold north: at a Fargo-like station the La Nina to El Nino swing was about 0.1 days, basically nothing. At a Houston-like station it was 8 days. The climate oscillation you hear about on the news moves the mild south and leaves the frozen north alone. Elevation is real but modest. At 40 degrees north, climbing from sea level to 1600 meters (think Denver) pushed the last frost about 13 days later. Real, worth knowing, but a quarter of February's pull. None of this is on a frost-date website, because those sites look up a static average by ZIP code. They cannot tell you what moves your number. A model you can interrogate can. That is the difference between a lookup table and something that has actually learned the shape of the problem. Why Does Open Innovation Matter? I kept asking: would a closed, hosted model have made this better? Every time the answer was no. Offline is the entire premise. The place you most need a frost date is the plot with no signal. A closed API cannot reach it. Open weights on your own disk work there. This is not a nice-to-have for FrostWise, it is the reason it exists. Your location is yours. "Where do you garden" is personal data. With open weights there is no server to send it to, no account to create, nothing logged. A hosted model turns your garden into someone else's row in a database. It costs nothing. Open weights mean zero per-request fees. A community garden can run it a thousand times and the bill is still zero. A metered API would make the same tool expensive at exactly the moment you want to share it. You own the brain. You can read how TabPFN predicts, retrain it on your own weather-station records, and swap Gemma for any open-weight model Ollama can run. Nothing is locked to a vendor you cannot inspect. If a forecast looks wrong, it is my data and my model to fix, not a prompt I have to beg a black box to honor. A closed API would have been faster to wire up for about an hour, and then wrong forever for the one person standing in a field with no signal. My Agent Session I built FrostWise with an AI coding agent, and I kept it honest the same way the app keeps its forecasts honest: the agent proposed, I verified every claim against a real run before it shipped. The useful parts of that session, in order: 1. Research before code. The agent read the challenge rules, the official template, and two past winning posts, then wrote the "why open beats closed" argument from the prompt's own bullets instead of guessing. 2. A feasibility spike first. Before a line of product code, it proved both models actually run on a plain CPU box: TabPFN-v2 predicting a frost date in about 3 seconds, and gemma3:1b answering a planting question offline. Only then did we build. 3. Catching my own overclaim. During review the agent flagged that the dataset is synthetic and made me say so in this post, rather than let "matches real climate norms" imply a live feed. That note is in "How I Built It" now because the agent pushed back. 4. Real bugs, found by running it. A static-path mistake made the UI load blank; a weak gemma3:270m ignored the frost date. Both were caught by actually running the thing, not by reading the diff. The through-line: the agent is fast, but nothing shipped until a real run backed it up. That is the same contract as the product. The model proposes, the evidence decides. Did It Touch Grass? I ran it for my friend's plot before she planted. FrostWise put her last frost in early May; she waited, set her tomatoes out the week after, and did not lose a single seedling to a late cold night. The screen part took about ten seconds. The rest of the afternoon she was in the dirt. That is the whole idea: the tool gets out of the way and sends you outside. Prize Categories - Best Use of Gemma. Gemma 3 runs locally via Ollama and writes every piece of planting advice. It is the whole language layer, offline, swappable, told the date so it cannot invent one. - Best Use of TabPFN. TabPFN-v2 (open weights) is the forecaster. It predicts the last-frost day-of-year from climate features in one CPU pass, with a calibrated range, no training required. The date on screen is always its number. --- Follow me for more on AWS architecture, DevOps, and AI Infrastructure: Portfolio | LinkedIn | dev.to | YouTube | [Email](mailto:simplynadaf@gmail.com) | AWS Builder Center | X