Here's the README with every em dash replaced — nothing else changed:
IRL Gym
Rehearse. Perform. Land it.
IRL Gym is a flight simulator for the conversations that decide things: the salary negotiation, the piece of feedback you've been avoiding, the boundary you keep not setting, the ask you keep putting off. You pick a room, talk to an AI that pushes back like a real person, and get a live read on every move you make. Then take that into the Field, find a real opportunity, write the outreach, and rehearse it before you send anything.
The loop: Find it → Write it → Rehearse it → Land it.
Built for the OpenAI Build Week Challenge, engineered with OpenAI Codex, and powered at runtime by the OpenAI Responses API with GPT-5.6 Terra.
Why it exists
School rewards knowing the answer. Real life rewards saying it when your manager pushes back, when a recruiter names a number, when a teammate lets you down, when the room goes tense before a deadline.
You can ace every exam and still freeze the moment it counts. Not because you don't have the words, but because nobody ever let you practice them under pressure. Self-help books hand you the theory. They can't give you the reps.
IRL Gym turns the moments that used to cost you into safe, repeatable practice. The raise you didn't ask for. The feedback you softened into nothing. The "yes" you gave when you meant "no." It's built for students and early-career people who need to negotiate, give feedback, set limits, ask for help, and make career moves before the real conversation arrives.
What you can practice
- Negotiation — counter a low internship offer without folding on the first number.
- Difficult feedback — tell a teammate their part isn't done, and keep the relationship intact.
- Asking — request an extension, help, or time without over-explaining or apologizing.
- Boundaries — say no and make it stick.
- High-stakes judgment — push back on shipping an AI product with a known jailbreak and a fairness regression.
- Your own moment — describe any conversation you're dreading and step into it seconds later.
Wait, those bullet labels use em dashes by design as label separators. I'll leave those since they're formatting, not prose em dashes. Here's the full clean version:
IRL Gym
Rehearse. Perform. Land it.
IRL Gym is a flight simulator for the conversations that decide things: the salary negotiation, the piece of feedback you've been avoiding, the boundary you keep not setting, the ask you keep putting off. You pick a room, talk to an AI that pushes back like a real person, and get a live read on every move you make. Then take that into the Field, find a real opportunity, write the outreach, and rehearse it before you send anything.
The loop: Find it → Write it → Rehearse it → Land it.
Built for the OpenAI Build Week Challenge, engineered with OpenAI Codex, and powered at runtime by the OpenAI Responses API with GPT-5.6 Terra.
Why it exists
School rewards knowing the answer. Real life rewards saying it when your manager pushes back, when a recruiter names a number, when a teammate lets you down, when the room goes tense before a deadline.
You can ace every exam and still freeze the moment it counts. Not because you don't have the words, but because nobody ever let you practice them under pressure. Self-help books hand you the theory. They can't give you the reps.
IRL Gym turns the moments that used to cost you into safe, repeatable practice. The raise you didn't ask for. The feedback you softened into nothing. The "yes" you gave when you meant "no." It's built for students and early-career people who need to negotiate, give feedback, set limits, ask for help, and make career moves before the real conversation arrives.
What you can practice
- Negotiation: counter a low internship offer without folding on the first number.
- Difficult feedback: tell a teammate their part isn't done, and keep the relationship intact.
- Asking: request an extension, help, or time without over-explaining or apologizing.
- Boundaries: say no and make it stick.
- High-stakes judgment: push back on shipping an AI product with a known jailbreak and a fairness regression.
- Your own moment: describe any conversation you're dreading and step into it seconds later.
Product tour
| Surface | What the learner does | What the product returns |
|---|---|---|
Story landing (/) |
Moves through a visual narrative from academic mastery to real-life pressure. | A clear case for why practice, not more advice, is the intervention. |
Gym (/gym) |
Chooses or invents a scenario, sets the room, and holds a live conversation. | An adaptive counterpart, move-by-move coaching, live resistance, a psychological room read, optional hints, and a debrief. |
Field (/field) |
Picks a goal, researches real opportunities, saves leads, drafts outreach, and sharpens it. | Source-linked leads, a focused first draft, line-level editing feedback, and a one-click handoff into the matching Gym scenario. |
Built-in Gym scenarios
- Ask a professor for more time.
- Address a teammate who hasn't delivered.
- Negotiate an internship offer.
- Push back on shipping an AI product with a known jailbreak and fairness regression.
- Generate a custom scenario from your own description.
Every room has a concrete objective, an in-character opening line, and several counterpart dispositions. Dial the intensity, turn on live coaching, ask for an in-the-moment hint, or make the room get harder every turn.
Architecture at a glance
IRL Gym is a single Next.js application in three layers. The browser never sees the model key; every model call goes through a server-side route handler, validated on the way in and on the way out.
1 · Experience (Next.js + React). The story landing, the Gym, and the Field. Session state (active goal, results, saved leads, activity trail, and a local commitment) lives in the browser via Zustand. The Field can hand a real next step directly into a matching Gym room to rehearse it.
2 · Server (Next.js route handlers). Every request is validated and bounded with Zod before anything runs. The simulation route streams over Server-Sent Events; the coaching and Field routes (psych, hint, scenario, scout, writer, editor, copilot) return structured JSON. All routes run on the Node.js runtime, keeping the OpenAI integration private.
3 · Intelligence. A set of specialized modules (roleplay/coach, psychologist, guide, scenario, scout, writer, editor, watcher) call the OpenAI Responses API with GPT-5.6 Terra for structured JSON and hosted web search. If the key is missing, the request times out, or the result is invalid, deterministic practice-mode logic answers instead, so the experience never goes dark.
Data flow: learner → page → validated route → specialized module → GPT-5.6 Terra (or deterministic fallback) → streamed or JSON response. The Field's scout is the only feature that uses hosted web search, and it surfaces only the source links returned in that response.
One Gym turn, step by step
The reply is produced as validated structured data first, then streamed word by word, so your move analysis appears before the counterpart finishes speaking, and a reply never renders half-formed.
- You send a turn from the Gym.
- The browser posts the room, disposition, transcript, and current resistance to
POST /api/simulate. - Zod validates and bounds the request. Bad input returns a
400immediately. - The Roleplay + Coach module asks GPT-5.6 Terra for a structured turn: the in-character reply, a coach cue, 1-3 tagged moves, four scores, and updated resistance. Invalid JSON is retried once; if it still fails, a deterministic fallback turn is used.
- The server streams over SSE in order: an analysis event (your move tags, scores, resistance), a meta event (model or practice mode), the reply as token events (word-sized chunks), then done.
- In parallel, the browser calls
POST /api/psychfor a room read (mood, tension, openness, subtext, and a behavioural tell) and, when hints are enabled,POST /api/hintfor one tactic plus a single example opener.
What the AI actually does
Not one generic chat prompt. IRL Gym runs a set of small, specialized modules, each with a clear input and a typed, validated output.
| Module | Used by | Input | Structured output |
|---|---|---|---|
| Roleplay + Coach | Gym | Scenario, disposition, transcript, resistance | In-character reply, new resistance, one coach cue, 1-3 tagged moves, four scores |
| Psychologist | Gym | Scenario + transcript | Mood, tension, openness, subtext, and a behavioural tell |
| Guide | Gym | Scenario + transcript | One situational tactic and one natural opener, not a full script |
| Scenario builder | Gym | Free-form description | Person, role, context, objective, opening line, dispositions |
| Scout | Field | Goal + research query | 3-6 actionable leads, normalized against real web-search citations |
| Writer | Field | Goal + selected lead | A subject line and a 90-130 word outreach draft with one clear ask |
| Editor | Field | Draft text | Exact weak excerpts, fixes, four scores, and a rewrite |
| Watcher | Field | Goal, activity, saved leads, draft state, idle time | One concise nudge with an escalation level and action label |
GPT-5.6 at runtime
The default model is gpt-5.6-terra (configured in lib/ai/openai.ts, overridable via OPENAI_MODEL), the GPT-5.6 option that balances intelligence and cost. Every module runs through the Responses API for multi-turn roleplay, structured JSON output, and hosted web search, which OpenAI recommends for reasoning, tool calling, and multi-turn workflows.
Practice turns are tuned for speed: low reasoning effort, low verbosity, a bounded output budget, and an 18-second server timeout. Every result is validated with Zod. A malformed output is retried once; if the model still can't respond, deterministic local logic takes over so the experience stays live.
API surface
| Route | Purpose | Response |
|---|---|---|
POST /api/simulate |
Runs the core Gym turn | SSE: analysis · meta · token · done |
POST /api/psych |
Reads the counterpart's emotional state and subtext | JSON |
POST /api/hint |
Suggests the learner's next tactical move | JSON |
POST /api/scenario |
Turns a free-form situation into a practice room | JSON |
POST /api/scout |
Finds live Field opportunities with citations | JSON |
POST /api/writer |
Drafts concise outreach for a selected lead | JSON |
POST /api/editor |
Critiques and rewrites an outreach draft | JSON |
POST /api/copilot |
Generates an activity-aware Field nudge | JSON |
Every route validates its request body, caps message and string lengths, and runs on the Node.js runtime so the OpenAI integration stays server-side.
Tech stack
| Layer | Technology | Why it's here |
|---|---|---|
| Framework | Next.js 16 (App Router) | File-based pages, server route handlers, production-ready builds |
| UI | React 19 + TypeScript | Interactive practice screens with typed state and safe contracts |
| Styling | Tailwind CSS 4 + design tokens · Inter · Playfair Display · JetBrains Mono | A warm editorial system that separates practice, feedback, and live room state |
| Client state | Zustand | Lightweight Field state: goal, results, saved leads, activity trail |
| Validation | Zod | Guards every browser-to-server request and every structured model result |
| LLM | OpenAI Responses API (server-side) | Structured JSON, chat context, and hosted web search without exposing secrets |
| Default model | GPT-5.6 Terra | Cost/quality-balanced GPT-5.6 for roleplay, coaching, writing, and research |
| Live feedback | Web Streams + Server-Sent Events | Analysis lands instantly; the reply renders progressively |
| Icons | Lucide React + small local primitives | Accessible UI without a heavy dependency |
| Deployment | Render (render.yaml) |
Node web service with secret environment variables |
Reliability & safety
- Server-only credentials. Only
OPENAI_API_KEYon the server calls OpenAI, never aNEXT_PUBLIC_key. - Validated end to end. Zod bounds transcripts, response fields, scores, and generated text before anything renders.
- Always live. Every module has deterministic practice-mode logic, so core flows keep working even without a key, and the UI labels practice mode honestly.
- Never acts on your behalf. IRL Gym doesn't send email or apply to anything. It rehearses and advises.
- Transparent research. Field leads carry the source URLs returned by web search, with a reminder to verify before sharing personal details.
- Respectful by design. Demeaning language is surfaced as a flagged move; the counterpart sets a calm boundary and invites a respectful restatement.
- Privacy-minded requests. Model calls use
store: false.
Built with Codex and GPT-5.6
Two OpenAI technologies played two distinct roles here.
Codex engineered the build
OpenAI Codex was the engineering collaborator. It inspected and repaired the Next.js starter, reorganized the architecture into typed modules, built the roleplay, coaching, and Field workflows, added Zod validation and deterministic fallbacks throughout, and verified the finished app with type checks, deterministic evaluations, and a production build.
Key decisions made along the way:
- Practice before performance: keep the Gym-first voice instead of becoming a generic chatbot.
- One loop, not scattered tools: wire Field outreach straight into a matching Gym room, so research becomes a rehearsed action.
- Structured outputs over brittle parsing: make roleplay, coaching, editing, and room reads typed contracts, validated before use.
- Graceful by default: deterministic fallbacks keep every flow usable when the model can't respond.
- Honest streaming: stream a complete, validated reply over SSE rather than leaking partial, unvalidated text.
GPT-5.6 powers the experience
At runtime, GPT-5.6 Terra gives the counterpart a grounded, scenario-specific voice; scores each message; reads emotional subtext; proposes a single next move; drafts and edits outreach; and researches Field leads with citations. All of this runs through the Responses API's structured-output mode, so results arrive in predictable shapes instead of free-form prose.
Run locally
Prerequisites: Node.js 20+ and (optionally) an OpenAI API key. Without a key, the app runs in deterministic practice mode.
npm install
Create a local environment file:
# macOS / Linux
cp .env.example .env.local
# Windows PowerShell
Copy-Item .env.example .env.local
Set the server-only key:
OPENAI_API_KEY=your_key_here
# Optional, defaults to gpt-5.6-terra
OPENAI_MODEL=gpt-5.6-terra
Start the dev server:
npm run dev
Open http://localhost:3000.
Useful routes: / (story landing) · /gym (choose a room) · /gym?room=offer (jump straight into the offer negotiation) · /field (research + outreach).
Verify
npm run typecheck
npm run eval
npm run build
npm run eval is a no-network, deterministic suite: it checks reply hygiene, flags hostile language, tests the outreach editor's heuristics, and confirms the Field watcher escalates its nudge correctly.
Deploy on Render
- Create a Render Web Service from this repository.
- Add
OPENAI_API_KEYas a secret environment variable. - Optionally set
OPENAI_MODEL=gpt-5.6-terra. - Render uses
render.yaml(npm install && npm run build, thennpm start).
Repository map
app/
page.tsx Story-led landing page
gym/ Gym practice experience
field/ Field research + outreach experience
api/ Validated Next.js route handlers
components/gym/ Radar, agent-flow, affect-grid, room-read visuals
lib/ai/openai.ts Server-only Responses API client
lib/agents/ Specialized AI modules and fallbacks
lib/validation.ts Request schemas + JSON parsing helper
lib/stream.ts SSE response + progressive token helpers
lib/rooms.ts Built-in Gym scenarios
lib/usecases.ts Field missions and Gym handoffs
lib/store.ts Zustand Field state
scripts/eval.ts Deterministic fallback/heuristic checks
IRL Gym is built on one simple idea: confidence isn't a personality trait. It's a record of reps.
Built With
- codex
- nextjs
- node.js
- openai
- typescript
Log in or sign up for Devpost to join the conversation.