Skip to content
Back to work

Built for a client · 2025

Bihotz

An adaptive coaching platform for runners. Training plans that bend with the week, not against it.

Bihotz

What it does — Bihotz is an adaptive coaching platform for runners (a coach dashboard plus an iOS app) built end-to-end for a running coach so his athletes' plans bend around real life instead of ignoring it.

The problem

The problem

Coaches who actually care about their athletes spend hours every week in spreadsheets. The hard work isn't writing the training plan once. It's reshaping it on Tuesday because someone has a 7am meeting, on Thursday because someone is travelling, on Sunday because someone slept four hours.

Off-the-shelf coaching software doesn't help with that. It captures runs and calculates loads, but it has nothing to say when a Tuesday tempo collides with an actual week. The athlete either does the session badly or skips it. The coach either rewrites the week from memory or shrugs and waits for next week.

The client running this practice (a coach with a small group of dedicated athletes) wanted something different: a system where the plan listens to the week. Adapt the work, don't shrink it. Get the most out of what each athlete can actually do, not less.

That's a real product. It needed a coach dashboard, an athlete app for iOS, a scheduling validator that knows what "36 hours after a hard session" means, a flag engine that surfaces problems early, and a check-in flow that captures life context before the week starts. As a solo developer, building all of that in a sensible amount of time used to be unrealistic. It isn't anymore.

My approach

I built Bihotz spec-first, then phase-by-phase against the spec. Five markdown documents lock the system before code touches it: STACK (tech choices), BRANDING (voice, palette, typography), DESIGN_TOKENS (design system), SCHEMA (data model), FEATURES (every screen, every flow). Each one is signed off before the next phase starts. By the time the first line of code shipped, the question "what does this surface do?" was already answered for every screen in the product.

Eight build phases

  1. 01

    Stack locked

    Framework, runtime, datastore, hosting decisions written down before scaffolding.

  2. 02

    Branding + design tokens locked

    Voice, palette, typography, motion. Tokens generated, no ad-hoc values in code.

  3. 03

    Schema + features locked

    Data model and feature surface defined in markdown before TypeScript.

  4. 04

    Scaffold + design system route

    Turborepo, packages, lint, type, route for visual regression on every primitive.

  5. 05

    MVP vertical slice

    Coach assigns, athlete logs, coach comments. End-to-end loop before feature expansion.

  6. 06

    Feature expansion

    Check-ins, alternative rules, rescheduling, impact, shoes, messaging.

  7. 07

    Social MVP

    Connections, match suggestions, external events.

  8. 08

    Polish

    Flag engine, notifications, i18n, accessibility, PWA install.

Mobile MVP port is in flight on top of that: magic-link auth, today shell, session detail, weekly check-in, week view with tap-to-reschedule, and an offline today cache covering the release-gating list.

The architectural choice that bought the most velocity was pure-TypeScript domain logic in a shared package. The validator that gates rescheduling, the flag engine that detects underperformance, the impact-score calculator: all live in packages/domain as plain functions with zero framework imports. The same code runs on web and on iOS. When the mobile app needs to know whether moving a Tuesday tempo to Wednesday violates a constraint, it calls the same function as the coach dashboard. One bug, one fix, two surfaces.

Key AI decisions

Key AI decisions

  • No user-facing AI.

    Every recommendation in Bihotz comes from the coach or from deterministic rules, never a model. The flag engine is hard-coded thresholds with explanations. The validator is explicit constraint logic. The placement defaults are constants. A runner shouldn't trust a model to decide whether today's session is safe. The coach knows, and the rules encode the parts the coach has already decided. Same principle as the "never hallucinate allergen data" rule in Glend, applied to a different category of safety.

  • AI as a build accelerator, not a feature.

    Claude Code paired with the locked spec shipped what would otherwise have been months of solo work in a fraction of the time. Each phase document fed the next phase as a tight scope. The model didn't make decisions. It implemented decisions that were already locked. The constraint of writing the spec first, and refusing to start coding until it was signed off, is what made AI tooling actually compounding rather than entropic.

  • Stack chosen for portability, not novelty.

    Next.js 16 with the App Router, React 19, Tailwind v4, Supabase Postgres, Drizzle for migrations, Turborepo for the monorepo, Expo for the iOS app. No exotic dependencies. Whoever the coach hires next year can read this codebase without asking permission.

  • Cross-platform domain logic in pure TS.

    Putting the rules in a shared package, instead of duplicating them on the API and again on each client, meant the iOS app and the web app validate identically. The validator returns a structured violations list with athlete-friendly explanations, not a boolean. That same structure renders as a modal on web and as a sheet on mobile.

Outcomes

  • Full web product shipped solo.

    Coach dashboard, athlete app, plan builder, alternative-rules configurator, flag engine, social layer, i18n, accessibility, PWA install. Every screen across the product is live.

  • Mobile MVP shipping.

    The iOS athlete app covers signup, today view, session logging, weekly check-in, week view with tap-to-reschedule, and an offline today cache.

  • Time-to-ship compression.

    Solo development with AI tooling delivered what would have been months of small-team work in a fraction of the time.

  • Handover-ready from day one.

    Five markdown spec documents (STACK, BRANDING, DESIGN_TOKENS, SCHEMA, FEATURES) tell the next maintainer what the product does and why, before they read a line of code.

What I'd do differently

What I'd do differently

  • Spec lighter at the leaves.

    The early phase docs over-specified some things that needed iteration anyway. The tagline locked, then re-locked. The typography choice was rewritten once when a tooling discovery flagged the original as generic. Lesson: lock the structure tightly. Leave the details room to move. The spec is a contract with future-you, not a prophecy.

  • Open the mobile app sooner.

    Building the web app to feature-complete before opening the Expo project meant some assumptions only got flushed when the iOS port picked them up: local timezone handling, offline state, magic-link auth flow on a non-cookie platform. None of those took long to fix. All of them would have been cheaper to catch with a mobile target in the room from week one.

  • Default more flows to audit-only, no notification.

    Several change-of-state flows were intentionally made silent. Athlete-initiated rescheduling, in particular, writes an audit row instead of paging the coach. That decision aged well: coaches read the audit when they're ready, instead of being interrupted by every move. Next time I'd start with audit-only and only add notifications where they earn their place.

What an Implementation Build looks like.

Bihotz is what the "AI Implementation Build" offering on the homepage looks like in practice. Spec-first, phase-by-phase, written down before code touches it. AI used as a build accelerator, not as a user-facing feature. Portable stack so the next maintainer doesn't need permission to read the code. If you have a real domain that should exist as software, and the cost of getting there has been the bottleneck, this is the pattern that gets it built.

If this kind of work could run inside your business, that's the conversation to have.

Bihotz is one of the patterns I bring into client work. The first 30 minutes are free, no slides.