Inspiration

Independent executive coaches do deeply human work, but their week looks like this: notes in one app, sessions in Zoom, payments chased over chat, client plans in a spreadsheet, conversations scattered across email and WhatsApp. The real signal — is this client actually changing? — is buried in months of notes, and it takes hours to decode.

Existing coaching tools mostly digitise the admin. Some state on their own websites that they use no AI at all, and none of them explain what happens when a renewal payment fails. We wanted to build the whole coaching relationship in one place: from the first prospect, through a PayPal checkout, to AI that reads a client's reflections and tells the coach what changed.

What it does

ExecutiveOS takes a coach from prospect to paying client to measurable progress:

  • Prospects and discovery calls. An AI-assisted Discovery Call Book researches the prospect's public links and drafts the call: questions, transition and fit check.
  • AI intake assistant + PayPal. The prospect chats with an assistant grounded in the coach's real programs and billing rules: what they pay today, when it renews, what happens if a payment fails. One click picks a program and opens PayPal checkout.
  • Real billing. One-time Orders v2 or auto-renewing Subscriptions. The moment PayPal confirms, ExecutiveOS creates the client's account and emails their sign-in. Failed renewals are retried up to 3 times; coach and client are notified after each failure, and the client becomes read-only after the last one until the coach reactivates them.
  • Coaching workspace. AG Grid for clients (grouping, master/detail rows, Excel export), a Bryntum calendar where dragging a session emails the client the new time, and AI Report Cards that summarise what changed, what's stuck and what to raise next session, quoting the client's own words as evidence.

How we built it

  • Frontend: React + Vite, shadcn/ui conventions, AG Grid Enterprise, AG Charts and Bryntum Calendar.
  • Backend: Express 5 API, PostgreSQL 16 with Prisma 7, Resend for email. Deployed as a single service (API + built web app) plus Postgres, with a Render Blueprint.
  • AI: LangChain and LangGraph, with Gemini first and Groq as fallback. Analysis is done by LangChain tool()s that work only over the client's own reflections: recurring patterns, contradictions, emotional trends, unresolved commitments. Each tool returns facts, dated quotes, a hypothesis and a confidence level, and the LLM only writes the narrative on top. The session brief is a LangGraph StateGraph: analyze → snapshot / explore / commitments / context → compose.
  • PayPal: OAuth client credentials with a cached token. A product and plan are created per program on first use with payment_failure_threshold: 3 and auto_bill_outstanding. Verified webhooks plus a periodic sync both feed one state machine, applySubscriptionState.
  • Demo video: built in code with Remotion. The UI is recreated from the app's own design tokens, the voiceover is synced word by word, and the music and sound effects are synthesised.

Challenges we ran into

Creating a client exactly once. A payment can be confirmed from three places at nearly the same time: the browser after approval, the PayPal webhook, and the periodic sync. Without care, that's three client accounts. We solved it by having completeIntakePayment claim the payment inside a database transaction, so only the first caller wins and the others become no-ops. If a subscription can't become a client (say, the email is already taken), it is cancelled rather than left billing.

Money is not a float. PayPal Subscriptions report "2500.0" while Orders report "2500.00". We never compare amounts as decimals; every amount is converted to integer cents first:

$$ \text{valid} \iff \operatorname{round}!\left(100 \cdot a_{\text{PayPal}}\right) = 100 \cdot a_{\text{program}} $$

Failure paths you can't trigger. The PayPal sandbox can't fail a renewal on demand, yet failed renewals are exactly the flow we wanted to prove. We added a sandbox-only Simulate failed renewal that records a failure through the same code path as a real one. With a threshold of $k = 3$ retries, a client gets at most $1 + k = 4$ billing attempts per cycle before they're paused.

Keeping AI honest. A coaching tool that invents a diagnosis is worse than useless. We split the work: deterministic tools compute every insight from the client's own words, and the model only writes them up. Every hypothesis is labelled as one, never presented as a diagnosis. The intake assistant gets the coach's programs and payment rules as input, so it can't make up a price. If no LLM answers, a deterministic fallback keeps the intake chat answering payment questions.

Privacy boundaries. Coach notes and AI insights are coach-only. The public intake chat tells prospects the coach can read it, blocks card numbers, and is rate-limited. Card details only ever go to PayPal.

Accomplishments that we're proud of

  • A real, end-to-end money flow: prospect → AI conversation → PayPal subscription → account created → renewals and failures handled.
  • AI that cites its evidence instead of guessing.
  • Sponsor tools used for real work, not as decoration: AG Grid grouping and exports, and Bryntum drag-to-reschedule with an email to the client.

What we learned

  • Payments are a distributed system. Webhooks arrive late, twice or not at all, so idempotency (PayPal-Request-Id, transactional claims) matters more than the happy path.
  • Grounding beats prompting. Passing the model structured facts and asking for structured output (reply, topic, actions, …) made the assistant far more reliable than clever prompt wording.
  • Fallbacks are a feature. Gemini → Groq → deterministic answers meant the demo never broke when a provider was rate-limited.

What's next for ExecutiveOS

  • PayPal Platform (partner) onboarding, so each coach is paid directly into their own account.
  • A coach sign-up flow and multi-coach practices.
  • Deeper progress analytics across a coach's whole client base.

Built With

Share this project:

Updates

Submission history