TM★
← All 35 projects

Crop Planning App

Blue Glass Farm2025★ greatest hit
Next.jsTypeScriptEvent SourcingSQLitePostgresClerkZustandPWAagentic engineering

Crop planning software that runs Blue Glass Farm's whole season. Drag plantings around a Gantt chart, reconcile the plan against what actually happened in the field, and use it offline from the field. Migrated by agents from five years of spreadsheet logic.

The crop planning app is the greatest feat of what I'll call vibe engineering I have ever achieved. It's the culmination of five years of software design for a very real problem our farm had. It started as an absolute monstrosity of a spreadsheet, grown out of a design from another farmer that I'd built custom software into until it became the software our farm needed. Over the years I built more and more functionality on top of it, until I finally outgrew what Excel could do and the whole thing was presenting a large amount of technical debt. I had wanted to turn it into an app for a long time. The reality was that the port was going to be incredibly time consuming. I had thousands of custom formulas in that sheet, thousands of lines of code built on top of them, and essentially a database of every way a market gardener might grow a vegetable crop. Around 2025, LLMs started getting good enough that I thought they could handle the larger pieces of that work. I could use the spreadsheet itself as the requirements doc, have agents figure out what the software did and what it would need to do, run the data migrations, build the business logic and a simple front end, and then I could get on with building the actual interfaces I had been dreaming of for five years.

Why leave Excel at all, when the workbook ran the farm for four seasons? Honestly, the spreadsheet having become a database was the real thing. One bad drag or one overwritten formula could quietly break the farm's year. There were also real limits on what I could do on the front end. Two-way data binding wasn't possible, which was annoying, and maintaining the software just sucked. It was hard to build new functionality into, and it was turning into a house of cards. Having the data grid was still a huge advantage, but the technical limitations had finally outweighed it.

Why not buy something? I'd looked. There were three or four options on the market, and they were all built from the outside. None of them fit our workflows well, and almost every one depended on the farmer importing their data through forms, one entry at a time. It would have taken us weeks to hand-enter the data we'd been running the farm on, and that fact alone kept us off all of them. Using them through a season looked no better. Most didn't support mobile well, most wouldn't work without a network, and most couldn't do multi-view layouts, which turns out to matter a lot. In Excel I can have the data grid on one side and the paper-doll view on the other and watch one change as I work in the other. In someone else's app I'd be reloading between screens all day. The interfaces were clunky, too. They felt like an ERP, not a design tool.

What I wanted to build solved all of those problems, and I could see how it could be done. Until now I just hadn't had the time to put it all together, because it was a huge undertaking.

The first decision was the method. Having the existing sheet meant I could do really solid regression testing. I had hard numbers from known configurations and could check that everything came out correctly end to end, so I could set the agent loose and let it work. It was the most tightly specced project I have ever worked on, and that's exactly what let the LLMs shine. The one ground rule I held was extract everything, transform nothing. Cleaning up legacy data on the way in is how you shred years of knowledge, because you can't always tell which oddball field is cruft and which one encodes a lesson that cost a crop failure to learn. All 340-odd planting configurations came across with every one of their 150-plus fields, and the workbook stayed in the repo as the source of record. What followed was a couple of months of the most intensive building I have ever done, in Next.js and TypeScript.

What's funny about a process like this is the human-error bugs. The agent would be trying to figure out some piece of logic that didn't make sense, and it would finally realize there was a bug in the spreadsheet. It's a bit like the argument that self-driving cars are safer than people because people make errors too. I've run into this time and time again with LLMs.

The other thing the migration taught me is that the model was missing base truths about farming. Days to maturity looks like the simplest number in a seed catalog, but it silently bakes in assumptions about how the plant is grown, direct-seeded or transplanted, and under what conditions. Claude kept treating it as arithmetic and kept being wrong, and it took me a while to realize the problem wasn't in the code. So I taught it. That's the real job of the domain expert in agentic work. You aren't typing the code. You're supplying the truths the model doesn't have, and vetting everything it builds on them.

Once parity landed, I could finally build the interfaces. I started with the Gantt chart view, being able to drag things around and move them easily, and have a planting break by length across multiple growing regions. But once I had it in my hands I started seeing the deficiencies, and I could try this, and this, and this. I ended up building entire other suites of views that solve different problems, and I rely on some of them more than the ones I originally envisioned. Being able to iterate on software that quickly means you can just test things. One of my favorite tricks cost almost nothing. Two open tabs share live state, so I can change a seeding date in one window and watch the Gantt chart move in the other. Normally that kind of sync has to go through a server that owns the truth, but a newer browser API, BroadcastChannel, lets my open tabs talk to each other directly and share the data without a single network call.

The app also pushes the plan further than Excel could. Planned dates and actual dates both exist and never overwrite each other, because the plan is the intent and the field is the truth. When a real date lands mid-season, everything downstream recomputes, so the plan reconciles with reality instead of drifting into fiction.

Underneath, configurations are the unit of planning, not crops, because spring carrots direct-seeded in April and fall carrots under row cover are different products with different economics. The data layer was the second big decision, and it started with a failure. I tried to normalize the data and realized very quickly that it didn't fit what I was doing. Each crop plan is a snapshot in time of a set of assumptions, which crops I'll grow, how I'll grow them, and what actually makes it into the ground. Over-normalize that and working on a new plan quietly rewrites history, which I didn't want. So plans are stored as documents. The patch log came from a different lesson, one I'd learned over years in Excel. Especially with multiple people working in a plan, it is so easy for something to creep in, and so hard to get back to a normal state afterward. So every edit is recorded with its inverse, which means we can see when something changed and why, and fish it back out of an otherwise good plan.

The third decision was where the data lives. I originally envisioned a distributed, SQLite-based architecture, inspired by Turso, because I've been a little obsessed with the idea of little micro-databases firewalled from each other running an application. It created all these interesting problems around keeping the databases in sync and updated, and it ultimately turned out to be more work than it was worth, though I'm still convinced there's a problem out there that Turso is the answer to. I eventually landed on plans living as blobs in a single Postgres database, Clerk for auth, and the same code running against local SQLite behind a clean data-layer abstraction, so we can go local-only or stay in the cloud depending on what we want in the future. For mobile we built it as a PWA, so we maintain a single codebase, we don't need any functionality that only a native app could give us, and it's easy for other people around the farm to install and use.

The scariest part of this project is that we used it to run the farm while we were building it. It was maintaining the operational blueprint for our entire 2026 season, with multiple people working in it, and if something had gone catastrophically wrong it would have caused real problems. And it worked. There were hiccups. Sometimes data propagated wrong. Sometimes we'd accidentally end up on the wrong plan, which meant UI work and backend logic to make sure a previously saved copy of a plan couldn't become canon. That one harkened back to the work I did for the gold company, keeping one canonical version of a plan. It has worked like a charm, and it will be how we run our crop plans from here on out.

My biggest takeaway from all of this was learning to trust what the AI was producing, by giving it strong tests, adequate logging, and protections, the same things you'd need with a large software team. Trust, yet verify. That lesson is what unlocked the power of agentic coding for me. Before this I had been hand-checking just about everything, and I realized I was the bottleneck. Set up the right supporting infrastructure and you really can set these tools loose on very important problems.

The last question someone might have is why I'm not releasing this as software. It's one of the most complicated pieces of software I've ever designed, on par with an ERP. The unit economics of farming don't really support selling it. Unlike an enterprise ERP, I can't charge tens of thousands of dollars a year for an installation, and farmers are less technically savvy than the average office worker, so the support load would quickly outstrip any benefit. I've thought a little about releasing it as open source. For now it's the secret sauce of our little farm in the Sammamish Valley.

Say hi.

Got a problem that looks like this one? I want it.
Got one so new nobody's even scoped it? I want that one more.