---
title: 'The Engineer Becomes the Editor'
author: 'Xinjiang Shao'
date: '2026-06-22'
draft: false
fullWidth: true
description:
  'I built a three-platform AI product alone for $725 of tooling and under $45/month to run.
  The interesting part was never the speed — it was what it changed about how I would lead a
  team.'
tags:
  [
    'Engineering Leadership',
    'AI',
    'LLM',
    'Side Project',
    'Career',
  ]
coverImage: './images/cover.jpg'
socialImage: './images/og.jpg'
seoDescription: 'I built a three-platform AI product alone for $725 of tooling and under $45 a month to run. What mattered was how it changed how I''d lead a team.'
---

I built [GroceryTrack](https://grocerytrack.food/) — web, iOS, and Android — by myself, in three
months, for about **$725 of AI tooling and under $45/month to run**. The
[full story of what it does and how it's wired](https://xinjiangshao.com/blog/2026-06-12-building-grocerytrack)
is its own post. This one is about a quieter thing the project kept teaching me: AI didn't just
change how fast I could ship. It changed what I think engineering leadership should optimize for.

The through-line is simple. The bottleneck moved from *writing* code to *judging* it — and once
that moves, the whole job moves with it, for an individual engineer and for the person leading
thirty of them.

## Capital Moved From Headcount to Judgment

Here is the cost structure of the entire product, stripped to two numbers:

| What it pays for | Monthly |
| --- | --- |
| The AI that writes the product (Claude, ChatGPT, Gemini) | ~$240 |
| Everything that runs it in production (GCP, inference included) | < $45 |

The model writing the code costs **five to ten times** more than the model serving every user.
That inversion is the headline most people miss when they talk about AI and software. We spent a
decade assuming the expensive part of software was operating it at scale. For a small AI product,
the expensive part is *producing* it — and "producing" now means directing and reviewing a model,
not typing.

Read that as a leadership statement and it gets uncomfortable in a useful way. If the cost of
turning a clear specification into working software is collapsing toward the price of the tokens,
then the scarce, expensive resource on an engineering team is no longer the capacity to *produce*
code. It's the judgment to decide what's worth producing, and the discipline to catch what the
machine got confidently wrong. Capital shifts from headcount-to-build toward judgment-to-direct.
That is a different thing to hire for, measure, and protect.

## At Ninety Percent, the Engineer Becomes the Editor

Most of GroceryTrack's code was written by a model with me directing — Claude Code as the primary
agent, with Gemini and Codex in rotation, because a second model is often the fastest reviewer of
the first one's output. Call it the ninety-percent tier: the model does the bulk, and my job
becomes writing the spec, reading the diff, and catching the mistake the model made with total
confidence.

That last part doesn't shrink as the model gets better. It grows. The faster code gets produced,
the more the binding constraint becomes how much of it a competent human can actually *judge* per
hour. Review throughput, not authoring speed, is the new ceiling.

For an individual contributor, this rewards taste over output. For a leader, it rewrites the
scorecard. Lines shipped and tickets closed were always weak proxies; at the ninety-percent tier
they're nearly meaningless, because the model can generate either one on demand. What I'd actually
measure on a team now is the quality of specs going *in* and the rigor of review coming *out* — the
two human-shaped bottlenecks the model can't yet remove. The senior engineer's leverage stops being
how much they can build and becomes how well they can direct and verify a machine that builds
faster than anyone can read.

## The Demo Was Free. The Production System Was the Whole Job.

A multimodal model reading a crumpled receipt is a five-minute demo. Shipping it to strangers is
everything wrapped around that model call — and that wrapping, not the prompt, is where the
engineering actually lives.

GroceryTrack's extraction path assumes the model will sometimes be confidently wrong, and is built
to catch it: schema validation on every response, sanity rules that encode domain truths the model
doesn't carry, retry logic for malformed output, and Sentry watching every failure so I see it
before a user reports it. The sharpest example is a date. An early user's receipt printed
`26/05/13` — YY/MM/DD — and the model read it as DD/MM/YY and filed her groceries years into the
past. A human never doubts a grocery receipt's date; a model has to be *told* receipts come from
the recent past. That one report became a validation rule that's held for every user since.

Three months in, I can put numbers on it. In the first week of reliable v1.3.0 tracking — 63
receipts, 792 line items, real users, me excluded — the engine cleared a usable parse 95.5% of the
time and extracted **line items at 97.9% accuracy**:

| Extracted field | Accuracy |
| --- | --- |
| Line items | 97.9% |
| Total / price | 92.1% |
| Date | 90.5% |
| Merchant | 90.5% |

But the headline hides the real lesson, and it's in the gap between those rows. By error *rate*,
the weak fields aren't the items — they're the receipt headers. The thing a person glances at and
trusts, the date and the store name, is what the model gets wrong most often, four to five times
more than any individual line item.

Two honesty notes, because a number like 97.9% should make you suspicious. First, "accurate" here
means "the user didn't correct it" — a genuine *lower* bound on error, since anyone who misses a
mistake counts as a success. Second, I can only measure my camera path at all: email-forwarded
receipts are parsed server-side and emit no client event, so right now I can't score them. Knowing
exactly where my own measurement stops is more useful to me than a cleaner number would be.

That last point is the part that transfers. The model is cheap; judgment about where it fails is
the scarce resource. The senior work was never writing the parser — the model writes the parser.
It's deciding which outputs get validated, which domain truths get hard-coded as guardrails, and
which fields a model is never allowed to persist unsupervised. At n=1, those are my own commits. At
thirty engineers, they're exactly where I'd want review attention concentrated — and where I'd
refuse to let "the model handles it" be the end of the conversation.

## The Hardest Decisions Were the Ones to *Not* Build

When producing software gets cheap, the constraint stops being *can we build it* and becomes
*should we*. That sounds obvious. It is brutally hard to live by, because the cost of saying yes has
dropped and the temptation to add has never been higher.

GroceryTrack's clearest example is its own paywall. About three percent of trials convert to Pro.
The reflexive move — the one every growth playbook recommends — is to optimize the funnel: tune the
paywall, add urgency, A/B the copy. For an early-stage product that's the wrong instinct. Conversion
optimization assumes the value is already there and you're just leaking it at checkout; this early
there's almost nothing to tune, and squeezing the funnel would only manufacture a number that
flatters me. The three percent matters for the opposite reason — not as a funnel to fix but as a
referendum on value. Payment is the one piece of feedback users can't fake; it's how they vote, in
the only currency that costs them something. Three people in a hundred voting *yes* is real signal
that the product is worth paying for to a narrow slice — and the ninety-seven voting *no* tell me,
more honestly than any survey could, that *photographing every receipt* is a high-discipline habit
most people won't adopt, and that the insights aren't yet worth four dollars a month to them. No
amount of paywall copy changes that verdict. The honest response is to fix the core loop until more
people vote yes, or accept the size of the niche — not to chase a conversion number as if it were a
dial to turn rather than a reading to heed.

I made the same call on platforms — and then on the project as a whole. Maintaining genuine feature
parity across web, iOS, and Android as a solo builder is a tax that compounds forever, so chasing it
was never the plan. Once Android ships and proves the cross-platform architecture, GroceryTrack moves
into a deliberately minimal mode: I keep working on it, but I cap myself to under five hours a month
and watch the running cost closely, because at this stage the marginal feature doesn't justify
open-ended maintenance. That's not a failure to finish. It's a deliberate decision about where my
scarcest resource — my own attention — goes.

This is the muscle I most want from a senior engineer and rarely see: prolific builders add;
leaders subtract. And the thing that earns you the right to subtract is data you've actually looked
at honestly. The three percent didn't tell me to try harder on conversion. It told me to stop.

## Architecture Choices Are Staffing Decisions

Every layer of GroceryTrack runs on deliberately boring, managed infrastructure — Firestore,
Cloud Run, Firebase, Stripe, Resend, Sentry. Nothing exotic, and that's the point. Shipping v1 in a
day was only possible because none of my time went into plumbing that a managed service does better
than I would.

For a solo builder, "use boring managed infrastructure" reads as a productivity tip. It's actually
the same instinct as a staffing decision. Choosing not to run my own auth, my own queue, my own
error tracking is the one-person version of *not* assigning a team to undifferentiated plumbing.
The one place I did spend real architectural thought — splitting the latency-sensitive scan path
from the batch path so a backlog of summary emails can never slow down someone scanning a receipt
in their kitchen — is the one place the decision was actually differentiating. Build where it
matters, buy where it doesn't. At n=1 that's a stack diagram. At scale it's a headcount plan, and
it's the same judgment either way.

## What This Changes About Leading Thirty Engineers

I lead a team in my day job, and I've spent years on the unglamorous work of consolidating
sprawl into something coherent. GroceryTrack didn't teach me leadership. It gave me a controlled,
single-variable experiment in what AI does to the *shape* of the work — and the answer is that it
pushes every part of the job toward judgment.

Concretely, here's what I'd carry into running a team in this era. Bring the AI toolchain in
deliberately, as a productivity multiplier, and be honest that its real cost is review, not tokens.
Restructure the workflow around specs and verification, because those are the bottlenecks the model
can't remove. Default to boring, managed infrastructure and spend the team's scarcest attention only
where the work is differentiating. And protect the discipline of subtraction hardest of all,
because it's the first thing to erode when building gets cheap.

## What I Don't Know Yet

I'd be lying if I dressed this up as proven. It's n=1. A solo project is not an organization, and
the habits that work when I'm the only stakeholder may not survive contact with twelve other
opinions. The retention signal I care about is real but small — a few dozen strangers, not a market.
My accuracy numbers are a lower bound from a one-week window, not a benchmark. And there's a whole
category of decisions — the ambiguous architectural bets, the calls that trade one team's velocity
for another's, the judgment about *which problem is even worth solving* — that the model can't
touch, and that I suspect it won't for a long time.

That's the part I find genuinely interesting, and it's the part I'd want to talk about with anyone
thinking about how engineering teams should actually work from here. The model writes the code now.
Deciding what's worth writing, and catching what it got wrong, is still the whole job.
