Skip to content

Blog

I'm building a SaaS at night while working at a Fortune 500 and raising a kid. Here's the math.

The math nobody publishes

Eight hours at the day job. Six hours awake with my son and partner. Two hours on the side project, 10 PM to midnight, most days. Eight hours sleep on a good week.

That’s the schedule. Most weeks I get 12-15 hours on the product. Some weeks the day job demands a fire and I get five. Some weekends the kid is sick and I get zero.

At 50 hours a month, that’s 600 hours a year. Most full-time founders burn 600 hours in a single month. The math says I should be 12x behind them.

Six months in: I’m not. Slower, yes. But shipping consistently, learning the same lessons (just slower), and — crucially — not running out of money or burning out.

I want to share what actually works at this pace because most “founder content” is written by people who quit their jobs. The side-hustle path is undermarketed.

Why I haven’t quit yet

Three reasons.

Stability removes desperation. I’m not building from financial fear. I can pick the right feature instead of the marketable one. I can spend a week fixing infrastructure that won’t show up in screenshots because there’s no urgency to fake progress. When you’re not running out of money, you can make slow decisions.

The day job teaches what NOT to do. I sit in 4-hour quarterly planning meetings. I watch products take 3 months to ship a button color. The contrast trains my speed instincts. Every time I open my laptop at 10 PM, I can ship in 25 minutes what a corporate team would schedule for next sprint.

The audience is built-in. My LinkedIn audience cares about “engineer at Fortune 500 builds side project” content. That’s the content I have. Doesn’t work without the day job context.

The conventional wisdom says quit, give it everything, the constraint of survival will force product-market fit. My experience: the constraint of survival forces something, but it’s often not PMF. It’s bad fundraising, bad customers, or burnout. Stability lets you wait for the right shot.

The actual schedule

Monday-Friday:

  • 7:00 AM — kid up, breakfast
  • 8:30 AM — at the day job
  • 6:00 PM — back home, family time
  • 9:00 PM — kid in bed
  • 10:00 PM — laptop open
  • 12:00 AM — laptop closed (mostly)

Saturday-Sunday:

  • One of these days is family-only, no laptop
  • The other has maybe 3-4 hours of focused work
  • Weekend hours are unreliable — plan around weekdays

That’s it. The 10 PM block is sacred. No phone. No Slack. No “quick check” on email. Two hours of clean coding.

The 2-hour evening block — what actually fits in it

I used to think 2 hours wasn’t enough to do anything real. Six months in, here’s what fits:

  • One bug fixed + one feature shipped
  • One new tool wired through the integration layer
  • One blog post written
  • One round of cold emails (5-10) personalized and sent
  • One full code review of my own work from the last month
  • One conversation with a beta tester (DM thread)
  • One Notion template written from scratch

What does NOT fit:

  • Two of the above
  • A 4-hour deep refactor
  • A real podcast appearance
  • A live coding session

The discipline isn’t “work harder.” The discipline is “do exactly one thing per evening.” Pick before you open the laptop. Don’t context-switch.

What I stopped doing

A list of things I stopped doing once I accepted the 12-hour-week constraint:

  1. Reading hacker news during work hours. I used to scroll for 20 minutes a day “for inspiration.” Now I batch it to weekends.
  2. Tracking every metric daily. Daily metric reviews are a procrastination loop. I look at numbers once a week.
  3. Writing roadmap docs. Nobody reads them. The work itself is the spec.
  4. Adding features users haven’t asked for. Easier said than done.
  5. Meetings with myself. I used to “plan the week” for 45 minutes on Sunday night. Now I write the weekly ship target on a Post-it, that’s it.
  6. Premature scale thinking. Optimizing for 10,000 users when I have 2 is just procrastination dressed up.
  7. Comparing myself to full-time founders. Their constraints aren’t mine.

What I started doing

  1. One ship target per week, written before Monday. Anchors everything.
  2. One personal email per day to a beta tester or specific ICP person. 30 emails a month, slowly compounding.
  3. One blog post per week (this is one). SEO compounds over 18 months.
  4. One free resource per month (Notion templates, frameworks). Lead magnets that demonstrate the product.
  5. A weekly “what I shipped” review every Friday night, 15 minutes. Brutal honest.
  6. Walking before the 10 PM block to context-switch out of day-job brain.
  7. A list of “would do if I had a full-time founder budget” that I check quarterly. Most things on it turn out to not matter.

The 6-month numbers

Side-hustle math, for context:

  • Followers grown: 90 → 370 on X
  • Waitlist signups: 92 (all organic)
  • Beta invites sent: 18
  • Beta accounts redeemed: 3
  • Active users: 2
  • Real customers (paid): 0 (still closed beta)
  • Hours spent: ~350
  • Hours per beta account: 116
  • Hours per X follower: 1.25

The hours-per-result math is awful. The compounding math is fine. The fundamentals (shipping consistently, talking to users, learning the lessons) are working. The amplification (distribution) is where the slow part is.

What I’d tell my 6-months-ago self

  1. You’re not behind. The pace is normal. Founders you admire took 1-3 years before anything worked.
  2. Distribution is the bottleneck, not building. Spend 50% of your time on distribution starting now. (I still don’t do this enough.)
  3. Pick a narrower niche. “Solo founders” is too wide. Pick a specific subgroup — side-hustle founders with day jobs, or domain experts going SaaS — and write FOR them, not for everyone.
  4. Build a free vehicle product early. A small free tool that pulls people into the funnel without committing to a SaaS trial. (I just shipped one — should have done it month 1.)
  5. Stop “saving” Product Hunt for “later”. Launch it on a small product to learn the mechanics. The first launch is always rough.
  6. The reply game is your most underused channel. Bigger account threads are where attention lives. Be there daily.

Why I’m still doing this

The honest answer: it’s the most meaningful work I do in any given week. The day job pays well and I’m grateful for it. But the day job hasn’t asked me to think hard in months. The side project asks me to think hard every single night.

That’s worth a lot. Even if the numbers stay slow, the I’m a person who builds things identity stays alive. I can’t put a dollar amount on that.

The day job and the side project teach each other. The corporate context grounds me in scale and stakeholder reality. The side project keeps me dangerous.

Where to find the work

I’m building aicofounders.co — 6 AI cofounders for solo founders who want a team without hiring one. Closed beta.

If you want to test it without signing up, run a free idea teardown. It’s the Product cofounder, running for free, on whatever startup idea you’re thinking about.

If you’re on the same path — day job + side project + kid or no kid — say hi. I read every email and reply within 24 hours: kyle@aicofounders.co.


This is post #2 of an ongoing build-in-public series. Subscribe to follow the journey from closed beta to first paid customer.

My LLM cost was 3x wrong for two months. Audit your own dashboard.

The trigger

I run a SaaS where every user interaction triggers LLM calls. The product is aicofounders.co — 6 AI cofounders that produce strategic output for solo founders. Token spend is the largest variable cost in the business.

Two months ago I built a per-user cost dashboard for the admin panel. Looked clean. Showed me $4.50/week in LLM cost. Felt expensive for 2 active users.

Made me nervous. Started slowing beta invites because the math felt fragile. Considered raising the Starter tier price from $29 to $39 to cover real cost. Deprioritized some token-heavy features.

Last week I looked at the dashboard again and noticed something. OpenRouter — my LLM provider router — returns response.usage.cost on every API call. The actual cost in USD, calculated by them, returned in the response.

I’d been ignoring it. My dashboard was using a static pricing table I’d built months ago, calculating cost from token counts. I wired up the real cost reading.

The corrected number for that same week: $1.50.

Three times less than I thought.

What went wrong

The static pricing table had this structure:

const PRICING = [
{ prefix: "anthropic/claude-haiku-4-5", input: 1, output: 5 },
{ prefix: "anthropic/", input: 3, output: 15 }, // catch-all
];

For two months, my product had been silently using anthropic/claude-haiku-4-5 (cheap, $1/$5 per million tokens). My pricing table HAD that specific entry — but a typo in the model name. The real model returned by OpenRouter is sometimes served as anthropic/claude-4.5-haiku (version before tier, different convention).

My exact-match check failed. Costs fell through to the catch-all anthropic/* which pointed to Sonnet pricing ($3/$15 per million). Three times the real cost.

The bug was invisible because:

  1. The dashboard “worked” — it showed numbers
  2. The numbers were plausible — $4.50/week feels like a reasonable LLM cost
  3. There was no error log because the catch-all matched correctly (just with wrong rates)

This is the most dangerous category of bug. Loud bugs you catch immediately. Silent bugs that produce plausible-but-wrong numbers can run for months.

Strategic decisions I made on bad data

In the two months when my dashboard was lying:

  • I slowed beta invites. Was worried about cost-per-user. Should have invited more aggressively.
  • I considered raising Starter pricing $10/month. Would have hurt conversion for no real reason.
  • I deprioritized features that consumed tokens. Specifically, the deeper research tools (multi-step reasoning, longer context). Those should have stayed.
  • I planned a tool-model swap to reduce cost on what I thought was the second-biggest token consumer. Turned out it wasn’t.

Four bad decisions, partially mitigated by being a careful person, but the bias was real. Bad dashboard data shapes product strategy in ways that look rational from the inside.

The fix

Two parts.

Part 1: read the real cost.

export function extractUsage(responseData: any) {
const usage = responseData?.usage;
if (!usage) return null;
const rawCost =
typeof usage.cost === "number"
? usage.cost
: typeof usage.total_cost === "number"
? usage.total_cost
: null;
const cost =
typeof rawCost === "number" && Number.isFinite(rawCost) && rawCost >= 0
? rawCost
: null;
return {
promptTokens: usage.prompt_tokens || 0,
completionTokens: usage.completion_tokens || 0,
totalTokens: usage.total_tokens || 0,
cost,
servedModel: typeof responseData?.model === "string" ? responseData.model : null,
};
}

When the provider returns real cost, use it. Static table is fallback only.

Part 2: backfill historical data.

Rather than just fixing forward, I wrote a script that walked every UsageLog row in the database, looked up the correct rate for the model recorded, and updated estimatedCost to match reality. About 5,000 rows. Total time: under a minute.

The dashboards now show truth all the way back to the product launch.

A checklist for anyone running LLM-powered SaaS

If you have a per-user cost dashboard and you’ve never re-verified the methodology, do it tonight. Bullet checklist:

  1. Read your provider’s response.usage.cost field if available. OpenRouter, Anthropic, OpenAI all return it. Use it as the source of truth.

  2. Match on both requested AND served model names. The model you REQUEST and the model your provider SERVES can differ in naming conventions. Catch both shapes in your pricing table.

  3. Add an explicit pricing entry for every model variant you use. Don’t trust catch-alls. When you add a model, add the entry. When you remove a model, remove the entry.

  4. Re-audit your cost methodology quarterly. Models update. Env vars change. Provider pricing changes. Your code didn’t notice.

  5. Track requested model vs served model in your log. Saved me a debug round when I needed to figure out which model was actually doing the work in production.

  6. Backfill historical rows when you fix the methodology. Otherwise your dashboards show two different truths — old wrong, new right — and your eyes will lie to you about trends.

  7. Cross-check by hand monthly. Pick a single user, look at their token spend in the dashboard, manually multiply by current rates, compare. Catches drift before it becomes habit.

What this cost me

Two months of slightly suboptimal decisions. No actual lost money — the real cost was always lower than I thought. But the opportunity cost of slowing beta invites and dragging on pricing decisions: probably one or two beta users who would have been ready to be paid converters by now.

The lesson generalizes beyond LLM cost. Dashboards lie. Especially the ones you built yourself. Especially the ones you stopped checking the math on.

Bigger principle

A founder I respect once told me: half your job is being skeptical of your own data.

If you can’t reproduce the dashboard math by hand on a single row, you’re flying blind.

If you haven’t re-verified the methodology in 90 days, the methodology is probably wrong.

If your strategy depends on a number in a dashboard, audit the number before you commit the strategy.

Where this work happened

I’m building aicofounders.co — 6 AI cofounders for solo founders. The cost dashboard described here is part of the admin panel that lets me run unit economics in real time.

Closed beta. Free idea teardown (no signup): aicofounders.co/teardown.


If you’ve caught your own silent dashboard bug, I’d love to hear the story. Reply on X or email kyle@aicofounders.co.