< Back to Blog

The PRD That Was Obsolete Before the Sprint Started

TL;DR / Key Takeaways

  • Corporate PRDs are often written by people who don't code, approved by people who don't ship, and handed to engineers as if they contain useful information.
  • The gap between "what the PRD says" and "what the engineer actually needs to know" is where projects go to die.
  • Solo builders don't need PRDs. The spec is the code. The feedback loop is immediate. The reviewer is you.
  • Predict & Profit was built with zero product managers, zero requirements documents, and zero sprint ceremonies. The bot either trades or it doesn't. That's the spec.

I spent thirty years reading PRDs.

Not learning from them. Not being inspired by them. Reading them, translating them from business English into something resembling an engineering task, and then watching the requirements change two weeks into the sprint while the document sat frozen on Confluence like a bug in amber.

I want to talk about why that process is broken, what it costs engineers, and what working without it actually feels like.


What a PRD Is Supposed to Be

In theory, a Product Requirements Document captures what needs to be built, why it needs to be built, and what success looks like. Clear problem statement. Measurable acceptance criteria. Enough context that an engineer can make good decisions when they hit edge cases.

That's the pitch.

In practice, a PRD is a Word document or a Notion page that a product manager assembled from Slack messages, one stakeholder interview, and a competitor's marketing site. It gets reviewed in a meeting. Engineering is invited to that meeting as a formality. Concerns are noted. Concerns are not incorporated.

The sprint starts Monday.


An Actual Example of the Gap

Here is the kind of language that shows up in real PRDs. I'm paraphrasing, but not by much:

"The user should be able to view their data in a way that is intuitive and provides actionable insights. The interface should feel modern and be consistent with the brand."

That's the requirement. That is the thing an engineer is supposed to build.

Here is what the engineer actually needed to know:

  • What data? Which fields? From which tables? Is it already aggregated somewhere or does this hit the raw transaction log?
  • What does "intuitive" mean to the PM? A table? A chart? A chart the user can filter? A chart the user can export?
  • What is the expected row count? Ten rows or ten million rows? Because that changes the entire architecture.
  • What does "actionable" mean? Does clicking something need to happen? Where does it go?
  • "Modern" and "consistent with the brand" are the design team's problem, not the data engineer's. Why is this in the requirements?
  • What is the deadline, and is it load-bearing or aspirational?

None of those questions are answered in the PRD. Half of them were never considered before the document was written. The engineer figures it out in a three-way Slack thread between themselves, the PM, and a designer who is on PTO until Thursday.

The PRD is not a requirements document. It is a conversation starter that everyone agreed to treat as a contract.


The Lifecycle of a Bad PRD

Week one: Engineering reads the PRD. Engineers raise questions. Some questions get answered. The rest are "parking lotted" for a follow-up meeting that never happens.

Week two: The sprint starts. Engineers make assumptions on the unanswered questions because the alternative is blocking. Assumptions are reasonable but wrong in two specific ways that nobody could have predicted without domain knowledge that lived entirely in the PM's head.

Week three: The PM sees a demo. The PM says "oh, I thought it would work like this other thing." The other thing was not in the PRD. Nobody is blamed. The sprint gets extended.

Week four: Stakeholder review. Stakeholder has a new idea based on seeing the demo. The idea is "small." The idea requires touching the data model. The sprint gets extended again.

Week six: The feature ships. The PRD is now partially inaccurate. Nobody updates it. It becomes the reference document for the next feature that builds on top of this one.

Repeat for thirty years.


Why This Happens

PRDs are written at the wrong time by the wrong people without the right information.

They're written before engineering is consulted, so they describe what the business wants without any grounding in what the system can actually do. They're written by people whose job is to translate business needs into documents, not to understand data flows or API constraints or the latent complexity hiding in a seemingly simple request.

This is not a personal failing. It's structural. The PM's job is to define the what. Engineering's job is to figure out the how. The problem is that the what is often technically incoherent, and nobody finds out until the how is already halfway done.

The best teams I worked on had engineers involved from the beginning of scoping. Not invited to a kickoff meeting after the PRD was written. Actually involved in figuring out what was possible. Those teams shipped faster and had fewer rework cycles.

They were also the exception.


What I Do Instead

When I decided to build Predict & Profit, there was no PRD. There was a question: can I find a real edge in Kalshi temperature markets using ensemble weather models?

The spec was: let's find out.

The first version of the weather bot was a script that pulled GFS ensemble data from Open-Meteo, calculated a probability distribution over temperature outcomes, and compared that distribution to Kalshi's market prices. If my model said 65% and the market said 48%, I had a candidate.

That's the whole requirement. Everything else was discovered by building.

When NOAA released AIGEFS in December 2025, the requirement became: add AIGEFS as a second ensemble source and weight it appropriately. No PRD. I opened the NOAA AWS S3 bucket, looked at the GRIB2 file structure, wrote a parser, and integrated it.

# AIGEFS fetch from NOAA's public AWS S3 bucket
# No auth. No NOMADS. No rate limits.
import requests

def fetch_aigefs_member(run_date: str, run_hour: int, member: int, forecast_hour: int) -> bytes:
    base = "https://noaa-nws-graphcastgfs-pds.s3.amazonaws.com"
    key = (
        f"graphcastgfs.{run_date}/{run_hour:02d}/"
        f"graphcastgfs.t{run_hour:02d}z.pgrb2.0p25.f{forecast_hour:03d}"
    )
    idx_url = f"{base}/{key}.idx"
    grib_url = f"{base}/{key}"

    # Parse .idx to find byte range for the variable we want
    idx_resp = requests.get(idx_url, timeout=30)
    idx_resp.raise_for_status()
    byte_range = parse_idx_for_variable(idx_resp.text, variable="TMP", level="2 m above ground")

    headers = {"Range": f"bytes={byte_range[0]}-{byte_range[1]}"}
    grib_resp = requests.get(grib_url, headers=headers, timeout=60)
    grib_resp.raise_for_status()
    return grib_resp.content

The requirement was "get the AIGEFS data." The implementation was figuring out that NOMADS rate-limited us after 868 requests, that the GRIB filter endpoint didn't exist for AIGEFS, and that the S3 bucket was the right path. That discovery process took a day. No PRD would have captured it because nobody knew it was going to be a problem until we hit the wall.

That's the difference. In corporate, hitting that wall triggers a requirements update, a stakeholder meeting, a revised timeline, and a project status email. When I'm building alone, hitting that wall means I fix it and move on.


The Spec Is the Code

This is the thing I could never say out loud in corporate without someone writing it up as a process concern.

For a solo builder, the code IS the spec. The behavior of the system at runtime is the source of truth. If the bot places a trade when it shouldn't, that's a bug. If the bot skips a trade it should have taken, that's also a bug. The acceptance criteria are not on a Notion page. They are observable in the trade log.

# This is the acceptance test
grep "TRADE_PLACED" bot.log | wc -l     # did anything execute?
grep "SKIP reason=" bot.log | tail -20  # what got filtered and why?
grep "ERROR" bot.log                    # did anything break?

If those three commands return sane output, the sprint passed. There is no sprint review. There is no retrospective. There is the log and there is the next trading cycle.

This sounds chaotic to people who work in product-led organizations. It isn't. It's just a tighter feedback loop. The "requirement" for the agreement filter (requiring 3 of 4 ensembles to agree before trading) came from watching the bot take trades during model disagreement and losing on them. The requirement emerged from production behavior, not from a planning session.

That's how requirements should work. You see the problem, you define the fix, you ship it.


What I Actually Miss About Corporate Process

Not the PRDs.

What I miss is the second set of eyes. When I'm building alone, the blind spots are mine alone. In a team, someone usually catches the thing you didn't think about. Not the PM, usually. Another engineer.

The econ bot's get_positions() bug is a good example. The function was reading the wrong key from the Kalshi API response. The bot literally could not see its own open positions. In a code review with one other engineer, that gets caught. Building alone, it made it to production and caused the bot to over-trade for a full cycle before I found it.

# What the code said (wrong):
positions = response.get('positions', [])

# What the Kalshi API actually returns:
# {'event_positions': [...], 'market_positions': [...]}

# What it should have said:
market_positions = response.get('market_positions', [])

One line. The kind of thing a second pair of eyes catches in thirty seconds. I caught it by reading the API response manually after noticing the position count looked wrong in the log.

Process exists for a reason. Bad process is the problem, not process itself. A lightweight engineering spec written by engineers, with acceptance criteria defined as observable system behavior, is a useful artifact. Fifty pages of business requirements that describe the user's "journey" without mentioning a single database table is not.


The Corporate PRD as a Cultural Artifact

I think PRDs in their worst form exist because organizations need to feel like they have control over complexity they don't actually understand.

Writing a document creates the sensation of having defined something. Reviewing it in a meeting creates the sensation of alignment. Neither the document nor the meeting actually solves the problem of building software, which is fundamentally empirical. You don't know what the hard parts are until you try to build it. The PRD pretends otherwise.

Solo builders don't have that luxury. There's no document to hide behind. Either the bot runs or it doesn't. Either the edge is real or the trade log shows a losing record. The feedback is fast and it is honest.

Thirty years of corporate process built an impressive tolerance in me for ambiguity theater. Building Predict & Profit burned most of it off.

I'll take the log file over the Notion page every time.


The bot is running right now on a RackNerd VPS in Atlanta, pulling GRIB2 files from AWS S3, comparing four ensemble models, and logging every decision it makes. No PRD was harmed in its construction. Use coupon code REDDIT for 15% off the source code if you want to see what a spec that lives in the code actually looks like.