comment with a stable id. - Do not rename ids; a later page build maps id -> component. - marks a blank only James can fill. - marks a claim that must be checked before sending. - marks a section awaiting the prototype build. ============================================================ -->
Deciding What to Build
A decision log for the MangoVoice product challenge — James Carlson, August 2026
Written while the work was still happening. The outcome is open, some of these decisions are probably wrong, and the parts I don't know yet are marked as unknown rather than smoothed over.1
1. The assignment
I came into this process sideways — as a reference for someone else's application, not as a candidate.2
Alicia's prompt, verbatim:
Identify a problem that interests you in any domain and use AI to take it from idea to a working prototype. Assume someone other than you will use it. Please send me what you built and describe your process by EOD Thursday.
I also carried three things she said in our conversation, and treated them as constraints on the answer rather than as pleasantries:
- Product is about solving the right problem, not just the solution.
- Involving developers early matters.
- Not building anything is sometimes better than building something.
The third one is the hardest to honor in a challenge whose deliverable is a thing you built. I've tried to honor it anyway, and section 4 is where that gets uncomfortable.
2. Deciding what to build
The constraint that shaped everything: I started a two-week work trial at another company on Monday morning. It's capped at fifteen hours a week, I'm in the final round there, and I wasn't willing to shortchange it. So the real question wasn't "what's the best possible thing to build." It was "what's the best thing I can build in the hours that are actually left."
That pushed hard against one obvious option: build something new and disposable purely to demonstrate the process. Throwaway builds are legitimate — you build to learn, then you throw it away, and the learning was the point. But that's the right move when the thing you need is knowledge. What I needed was a working prototype someone else could use, and I already had a list of ideas that had never gotten past the idea stage because I could never find the time.
So I inverted it. Rather than invent a problem for the challenge, I screened the problems I already had against Alicia's prompt: does it interest me, is it real, can AI take it from idea to working prototype, and can somebody other than me actually use the result.
| Idea | Problem is real to me | Usable by someone else in days | Blocked on anything | Verdict |
|---|---|---|---|---|
| Latestfile | Yes — felt it directly | Yes — spec and schema already exist | No | Selected |
| Diamonds in the Rough | Yes — my own layoff | No — too early | Entangled with a live co-founder conversation | Rejected |
| Lendio AI-usage pilot | Yes | Yes | I no longer work there | Rejected |
The one that had gone furthest was Latestfile.
I bought the domain latest.dev back in . I have wanted to make it
into something ever since and never had the runway to do it. What changed is that AI
collapsed the cost of the work — a spec, a schema, reference implementations, and a
site are no longer a season of evenings. That's not incidental to this challenge; it's
the same shift the challenge is asking me to demonstrate.
3. Why Latestfile
Everyone is talking about AI, and almost everyone is talking past each other.
Ask ten engineers at the same company how they use AI and you get ten different answers, none of them written down anywhere you can find. One lives in Cursor with autocomplete on and privacy mode off. One drives Claude Code through a wall of custom instructions. One pastes into a chat window and copies back. One routes through a personal API key nobody in security has heard of. Multiply that across teams and you get the question every leader is now asking and nobody can answer: how do we actually use AI here?
It matters more than it sounds, because the performance swings are enormous and they hinge on small things. Which model. Which harness. Whether someone wrote good instructions. Two engineers with the same license and the same task can be an order of magnitude apart, and the difference lives in configuration nobody has written down.
Latestfile is the proposal that this be declarable — with the specificity of code.
A small, readable, version-controlled file that states how a person, team, or
organization uses AI: tools, models, workflows, instructions. It composes: a personal
file rolls up into a team's, a team's into the org's. package.json for AI usage.
Descriptive, not prescriptive — it captures what's in use, not what's allowed.
We've made this move before, repeatedly. Untracked dependencies became package.json.
Hand-clicked infrastructure became Terraform. Crawler guesswork became robots.txt.
Doc ingestion became llms.txt. None of them are clever. They're all the same move:
take a practice living in people's heads and give it a small portable file that
travels, diffs, and composes.
Honest scorecard on the idea when I picked it back up:
- For it: I had felt the pain first-hand, the spec was already written, and the cost of finishing was now low.
- Against it: I had no evidence anyone else wanted it. Not one conversation, not one signup, not one request.
I chose not to spend this week's hours on demand interviews. That's a real trade and I want to be explicit about it rather than let it pass — section 5.
The tooling: Claude Code, plus gstack and
gbrain — an open-source suite of Claude Code skills written by Garry Tan, President
and CEO of Y Combinator. Among other things, it runs a YC-style office-hours critique
against your own idea. That is what pushed the spec harder than I would have pushed it
alone, and it is where the initial launch plan came from.
Worth naming what that means about the process: the sharpest early pressure on this idea came from a tool, not a person. That is not a substitute for talking to users — see section 5, where it is precisely the thing I still haven't done — but it is a real change in what one person can subject their own thinking to before showing it to anyone.
4. The gap, and the layoff
Here is the part that doesn't flatter me.
May 15, 2026. I wrote the first Latestfile spec design document.
May 15–23. I finished v0.1: RFC 2119 normative language, four scopes, a JSON Schema, four reference Latestfiles covering personal, team, org and project, all schema-validated. I ran adversarial reviews against my own spec and revised twice.
May 23 – July 28. Nothing. Two months of silence.
July 28. Two things converged: my employer said publicly that it wanted to understand how AI was actually being used in order to set policy, and the broader "we're not getting the ROI from AI" complaint was everywhere. That was the moment. In one night I wrote the manifesto and built the landing site.
July 28 – August 19. Nothing again. Never deployed. Never shown to a single person.
August 12. The RIF.
So the honest accounting is: fourteen weeks, a finished specification, a JSON Schema, four reference implementations, a manifesto, and a landing page — and zero external validation. Not a soft launch that underperformed. Nobody had ever seen it.
Alicia's third insight was that not building anything is sometimes better than building something. I had spent fourteen weeks building on an assumption I never tested. I'm not going to pretend the challenge is what taught me that. What the challenge did was create the forcing function I hadn't created for myself, and that is its own uncomfortable finding: I needed an external deadline to do the thing I already knew I should do.
5. The riskiest assumption
Stated plainly: I don't know whether anyone but me wants this.
Everything else is comparatively safe. I know the format works — it's specified and schema-validated. I know I can build it — the site exists. I know the pain is real for at least one person, because I'm the one.
What I don't know is whether it's real for anyone else, and every hour I spend on polish before answering that is an hour spent on a possibly-worthless asset.
There were two ways to test it in the hours available:
Talk to people. More rigorous. Better information. Also slow, and in this window it would have consumed the entire budget and produced a report rather than a prototype — which is not what was asked for.
Ship it and watch. Faster, noisier, and it produces the artifact the prompt actually calls for. A working prototype is itself a demand instrument: it either draws signal or it doesn't, and either answer is more than I have now.
I chose to ship. What I'm giving up by choosing it: a null result is ambiguous. If nobody engages, I won't know whether the idea is wrong or the distribution was. I'm accepting that ambiguity because the alternative was to arrive at Thursday with a well-researched opinion and nothing anyone can use.
The standard name for this is a riskiest-assumption test. I want to be straight that the name came after the decision, not before it. I didn't consult a framework; I made a call under time pressure and the framework is a decent description of its shape.
6. What I built, and what I cut
For a reader who doesn't care about the internals: it's a website where you answer a
few questions about how you use AI, and it hands you back a file describing it plus a
public page at latest.dev/@yourname you can send to someone. No account, no login,
about two minutes.
Three things exist:
/new— a builder. You pick tools, models, and workflows; it writes a valid Latestfile as you go and validates it live./validate— a checker. Paste or upload a file, get every problem at once with line numbers./@handle— the result. A public profile page rendering your file, with the raw file served at/@handle/latestfileso a machine can fetch it too.
Underneath: roughly 2,600 lines, of which the interesting part is an HCL lexer and parser written from scratch, a 700-line validator, and a small storage layer.
The cuts, and why
No login, no accounts. The single most important cut. The moment a prototype has signup, the thing you learn is how many people will create an account, which is a different and much worse question than whether anyone wants the format. Claiming a handle returns a one-time edit token instead. It's weaker security than a password and it is the right trade at this stage: the cost of being wrong about the format is that I wasted fourteen weeks, and the cost of being wrong about auth is that somebody has to re-claim a handle.
No database. Storage is a key-value store, because the data model is a dictionary:
every read is "here's a handle, give me the record." No queries, no joins, no
aggregation. Adding Postgres would have bought a SELECT ... WHERE slug = $1 that does
what GET profile:acme already does, in exchange for provisioning, migrations, and a
connection pool. The threshold where that flips is specific and I want it on the
record: the moment I want to ask questions across profiles — which tools are most
declared, how do teams differ — I need a query engine, and that's exactly the analysis
layer the spec names as a downstream use. It's the second version, not this one.
Deferred: the composition demo. Latestfile's most interesting claim is that files compose — personal rolls up into team, team into org. It's specified, and it is not demonstrated in the prototype. That's the biggest honest gap in what I'm shipping. I cut it because the composition demo only means something once individual files exist, and nobody has written one yet.
Where the judgment was mine
The prompt is about using AI to get from idea to prototype, so it's worth being precise about where the model drove and where I did.
The model drove: the parser and lexer, the validator's structure, the route scaffolding, most of the CSS. I did not hand-write an HCL tokenizer, and I would not have finished this week if I had.
I drove these:
Validation runs in the browser, and nothing is uploaded. This is why the parser is hand-written rather than pulled from a package — the real HCL parsers are server-side or ship a wasm payload. The requirement came first and the implementation followed from it. A file describing your company's AI tooling is not a thing people should have to POST to a stranger's server to check.
Unknown blocks and unknown fields are warnings, not errors. The spec requires parsers to tolerate what they don't recognize, so that old tools don't break on new files. A validator that rejects anything unfamiliar would be more "correct" and would quietly sabotage the format's ability to evolve. That's a product decision expressed as an error severity.
You get every validation error at once. Parse errors stop at the first one, because after a syntax error the parser doesn't know what it's looking at. Validation errors are collected in full, so you fix everything in one pass instead of playing whack-a-mole with a form that reveals one problem at a time.
I rewrote the manifesto in my own voice. It was AI-drafted in July and I never finished making it mine. I spent a meaningful share of today's remaining hours on that rather than on features. The argument only works if it sounds like a person making it, and a manifesto in a model's voice asking people to adopt a standard is self-defeating.
I stopped myself from launch-planning too early. Partway through I started sketching the Hacker News and LinkedIn sequence, then asked whether that was premature and decided it was. Finish the thing, then sequence the launch.
7. How I worked
Two AI sessions running in parallel, deliberately separated.
One session built the product. A second session — this one — wrote the record. They were pointed at different repositories and never shared a context window.
The separation was the point. A single session writing both would have been marking its own homework: the same context that made a decision would be narrating why the decision was good, from memory, with every incentive to make the story tidy. Instead the record session reads the build session's git history and transcripts as primary sources. When I claim something happened, it's because there's a commit or a message showing it, not because I remembered it that way. Several details in this document came back at me from that reading in a form I would not have chosen — the fourteen-week gap in section 4 being the obvious one.
The handoff between sessions is written, not live. Trying to keep two AI contexts in sync in real time is a losing game; a checkpoint file that either session can read is not.
Where it broke. Partway through I lost track of which repository I was drafting the manifesto in, and spent a stretch reviewing a stale copy while the current one sat elsewhere. That's a real cost of splitting the work across sessions and I'd rather name it than present the method as frictionless. The fix was boring — check which repo you're in before you trust what you're reading — but the failure mode is worth knowing about if you're going to work this way.
8. What would make me kill it
9. Decision log
D0 — Write this as a decision log, not a case study
- Chose: A real-time decision log with open outcomes.
- Rejected: A case study.
- Why: The product isn't finished. A case study about an unfinished product has to invent an ending or hide the absence of one. A decision log is also harder to fake — it's timestamped against a git history — and the prompt asked me to describe my process, not my results.
- What would change my mind: If the prototype had been done and had users, a case study would be the stronger format.
D1 — Use a domain I know cold, not a MangoVoice problem
- Chose: A problem from my own life.
- Rejected: Building something for MangoVoice's business — voice, telecom, call center analytics.
- Why: Alicia's first insight is that product is about solving the right problem. You cannot demonstrate problem selection by guessing at somebody else's business from the outside, and a plausible-looking outside guess is exactly the failure mode she was describing. I do have real background here — I ran call center analytics for Texas Tech Physicians and took the abandon rate down 178% and queue time down 248% — which is precisely why I know how much context those numbers required and how little of it I have about MangoVoice.
- What would change my mind: If the prompt had asked for a MangoVoice-specific build, or if I'd had access to real users inside their domain.
D2 — Latestfile over Diamonds in the Rough
- Chose: Latestfile.
- Rejected: "Diamonds in the Rough," an idea about laid-off talent that came directly out of my own RIF.
- Why: Two reasons. It isn't far enough along to demo by Thursday, and it's entangled with a live co-founder conversation that isn't mine alone to publish.
- What would change my mind: More runway, and the other party's agreement.
D3 — Kill the Lendio pilot angle entirely
- Chose: Drop it.
- Rejected: A one-pager pitching Lendio's VP of AI on a free Latestfile pilot — already drafted, and a genuinely warm lead.
- Why: I was laid off from Lendio on August 12th. Pitching them isn't appropriate, and it isn't a question of whether the pitch would land.
- What would change my mind: Nothing this week.
D4 — Ship rather than interview
- See section 5.
D5 — No login, no accounts
- Chose: Claim a handle, get a one-time edit token.
- Rejected: Signup with real auth.
- Why: Auth converts the experiment from "does anyone want this format" into "will anyone create an account," which is a different question with a worse answer rate. The downside of getting auth wrong here is that somebody re-claims a handle.
- What would change my mind: Anyone storing something they'd be upset to lose.
D6 — Validate in the browser; write the parser by hand
- Chose: A hand-written lexer and parser so validation runs client-side.
- Rejected: An existing HCL parser, server-side validation.
- Why: A file describing your organization's AI tooling shouldn't have to be uploaded to a stranger's server to be checked. Existing parsers are server-side or ship wasm. The privacy requirement dictated the implementation.
- What would change my mind: Nothing. This one I'd defend.
D7 — Key-value store, no database
- Chose: Redis (Upstash). Atomic
SET NXso simultaneous claims have one winner. - Rejected: Postgres.
- Why: The access pattern is get-by-key. A relational database would add migrations and a connection pool and buy nothing.
- What would change my mind: The first question that spans profiles rather than addressing one. That's the analysis layer, and it needs a query engine.
D8 — Unknown blocks are warnings, not errors
- Chose: Tolerate what the validator doesn't recognize; flag it as a warning.
- Rejected: Reject unrecognized input.
- Why: Forward compatibility is required by the spec. A stricter validator would break old tools against new files and stop the format from evolving.
- What would change my mind: Nothing at v0.1.
D9 — Rewrite the manifesto in my own voice
- Chose: Spend hours I did not have rewriting AI-drafted prose.
- Rejected: Ship the July draft and spend the time on features.
- Why: I'm asking people to adopt a standard. That argument only lands in a human voice, and it's the piece I'd have to defend in a room.
- What would change my mind: Nothing, though I'd have started it sooner.
D10 — Defer launch sequencing until the build was done
- Chose: Finish the prototype first.
- Rejected: Planning the Hacker News / LinkedIn sequence mid-build.
- Why: I caught myself doing the fun part early. Launch planning against a thing that doesn't work yet is procrastination wearing a strategy costume.
- What would change my mind: If distribution were the riskiest assumption. It isn't; demand is.
10. What someone else can do with it
Colophon
Built with Claude Code. This document was drafted in a separate session from the prototype, deliberately, so that the record of the process wasn't being written by the same context that was making the decisions.
Footnotes
-
I considered writing this as a case study and decided against it. A case study is written after the fact with the outcome already known, which is why case studies never contain a decision the author got wrong. The product here isn't finished, so a case study would have to invent an ending or hide the absence of one. See D0. ↩
-
Danielle, a PM at Lendio, asked me to be a reference for a job she was pursuing at a company called MangoVoice. I said yes, and spent a call with Alicia Cawley talking about Danielle's work. Danielle got the offer and took it. Lendio counter-offered and kept her.
That could have been the end of it. Instead I kept sending Alicia names — people I thought were good who might be a fit. My brain works that way; connecting people is something I do reflexively whether or not there's anything in it for me.
On August 12th, Lendio ran a reduction in force and I was impacted. My first instinct was still to send Alicia more names, since a lot of good people had just become available at once. Somewhere in the middle of writing that message it occurred to me that I could throw my hat in the ring myself.
Alicia offered to meet. I rewrote my resume as a product management resume rather than an engineering one — — and we talked on . She moved me to the next round. ↩