all builds >> N. GUGLIELMI
>> nicola@guglielmi ~ / labs / thenegotiator

TheNegotiator

A gamified trainer where you practice high-stakes deals against a lifelike AI counterpart that pushes back, and get scored on every move. Built to answer one question: can you put a live LLM at the center of a product and still have it be demo-proof, deterministic to grade, and safe to ship?

Genkit Gemini Structured Output Next.js Firebase Cloud Run
>> THE_PROBLEM

Negotiation is a skill you only build by doing it against someone who fights back, and most people never get the reps. An LLM is the obvious sparring partner. The trap is equally obvious: an app whose core loop is a live model call is fragile in exactly the moments that matter. The API key is missing on stage, the model returns prose you can't score, latency spikes mid-demo.

TheNegotiator treats those failure modes as first-class design constraints, not edge cases to apologize for. The AI is the star of the product, and the product still works when the AI is unavailable.

>> ARCHITECTURE
Next.js game clienta turn · gamified state Genkit typed flows Opponent flowpersona · difficulty Scoring flowstructured output Coach / Scenario flowtyped schemas Geminivia Genkit Scripted engineno-key fallback Firebaseauth · Firestore · per-uid progress, streaks, XP move if no key typed score → client

> the client never talks to a raw model. it talks to typed flows that either call Gemini or fall back, and always return the same shape.

>> IN_ACTION
A live negotiation round against Marcus: his opening line, the player's counter, and his in-character reply pushing back with other options
> a live round against Marcus, on the scripted fallback (no API key). he pushes back in character, name-dropping "other options at better terms"; every move is scored.
>> DECISIONS_THAT_MATTERED
[ 01 ]

Plays with, or without, the AI

Every Genkit flow has a scripted fallback. Give it a GEMINI_API_KEY and the opponent is live; take it away and the game still runs on deterministic scripts. The product demos on a stage with no wifi and ships without betting availability on a third-party API. Graceful degradation is built in, not bolted on.

[ 02 ]

Scores are data, not prose

Every move is graded through structured output: the model returns typed JSON the game logic can trust, not a paragraph someone has to parse. That's what makes XP, streaks and leagues actually work, the scoring is deterministic to consume even though the reasoning behind it is generated.

[ 03 ]

AI as typed flows, not loose prompts

Opponent, coaching and scenario generation are separate Genkit flows with input and output schemas, not ad-hoc prompt strings scattered through the UI. Each is composable, swappable and testable on its own, and the client only ever sees a stable contract. The AI layer has a shape you can reason about.

[ 04 ]

Reproducible from the first clone

The whole dev environment runs in a container (Podman), with dependencies in a named volume so the host machine stays clean. One script starts it; there is no "works on my machine." The same discipline carries the app to Cloud Run, and Firebase handles auth and per-user progress with rules that isolate each player's data.

>> WHY_THIS_MATTERS_TO_YOU

TheNegotiator is a game, but the constraints are the ones every serious AI feature hits: don't let a third-party model be a single point of failure, make the AI's output a typed contract so the rest of the system can trust it, and structure the AI as flows you can test instead of prompts you hope work. Put an LLM at the center and still sleep at night, that's the job.