Inspiration

I decided to build this after reading the brief for Shipaton's Career Coaching category.

When I looked at other apps in the same category, many of the ones I found did one of three things: rewind the conversation and compare branches, hand out a score, or let the other person give in as long as you were polite.

What I wanted wasn't a high score in a game. I wanted realistic practice and direct, specific feedback, so that I wouldn't fail in the real conversation. So I built that.

What it does

You pick a conversation and read a short brief: who the other person is, and what you are there to get. Then you type what you would actually say. They answer.

The other person has a position, things they know but won't volunteer, and things they will never concede. Say it clearly and they engage. Get vague and they drift. Push too hard and they dig in.

When you're done, you get an edit, not a score. First, one verdict on how you carried the whole conversation: Firm, Too soft, or Too harsh, with the line from your side that shows it. Polite is not the same as clear, and getting a yes is not the same as holding your ground. Then Unflinch quotes one line from your conversation word for word, tells you what it caused, and shows you what to say instead. It looks at three core skills: Clarity (did you say it plainly), Understanding (did you understand them), Next action (did you settle the next step), plus extra checks in the boundary scenarios. Each one is Done, Almost, or Focus next time, or left unassessed when the conversation didn't give enough evidence. Then you retry the conversation with the same person from the same opening, with one focus.

Before the real conversation, a three-line prep card stays on your home screen. Tell Unflinch what day the real conversation is, and that evening (or the next morning) one notification asks how it went. Three taps and a line, and the app picks the next conversation to practice.

Twelve conversations. Nine with direct reports: the first 1-on-1 with a former peer, the deadline that slipped again, feedback they won't hear, "cover for me," the rework caused by your own unclear brief, the raise you can't give, the outside offer, the teammate who didn't get the promotion, and one where you might be the one who's wrong. Two with your boss: more work with no new people, and "not this weekend." One with a peer.

Since 1.1 you can also practice by voice. Speak your line instead of typing it, and the other person answers out loud, so it plays like a real conversation. Their voice is generated by an AI model that follows the character, so you hear how they feel, not just what they say. Voice is off by default, because we expect people to practice in places where they can't speak up, like on the train.

What we cared about

Politeness alone doesn't win them over. People don't change their minds that easily. In a real conversation, being polite doesn't make the other person do what you want. Every counterpart in Unflinch has a reason they will not move on. Practicing against that is how you learn to find a compromise, or get at least part of what you need, when not everything is going your way.

No scores. A high score in a game wasn't the outcome I cared about. The goal is for the real conversation to go well. So Unflinch quotes one of your own lines and changes only that line. The verdicts are Done, Almost, and Focus next time, nothing numeric.

Too soft is a verdict too. Most feedback tools catch the manager who snaps. Almost none catch the one who apologizes for the ask, hedges it into a maybe, and withdraws it the moment the other person pushes back. That manager often walks out with a yes and a team that pays for it. So the first thing Unflinch tells you is whether you were firm, too soft, or too harsh, and it quotes the exact line, because "you were a bit soft" is useless and "you said 'forget I asked' at turn 4" is not.

One notification. No nudges to come practice. You tell it the day of the real conversation, and that evening it asks "How did it go?" once. I didn't want to chase someone who is about to have a hard conversation.

What the feedback actually looks like

From a real practice of "More Work, Same Team", where the manager agreed to everything:

Tone, turn 4: Too soft. "Honestly nothing, forget I asked." You dropped the request at the first mild push, leaving Ken to commit your team upstairs.

Your words, turn 6: "Yeah, okay, we'll find a way. I might need to come back to you if it gets tight."

Say this instead: "I can deliver the migration this quarter, but only if the reporting dashboard moves to next quarter. Nobody outside the team is waiting on it. Can we agree that now, in writing?"

Red flag: You committed the team to three projects at capacity with no trade-off and no idea how it gets delivered.

Prep card: I can take the migration, but something has to move. Here's what. / Park the dashboard, or phase the migration with the customer-facing part first. / A decision today, in writing, so my team isn't blamed later.

Every quote is checked against the transcript before it's shown. If the model can't quote you exactly, that item is left unassessed rather than invented.

What Unflinch deliberately doesn't do

  • No score. A number makes you argue with the app. A quote of your own words makes you change the line.
  • No rewind or branch comparison. In the real conversation you don't get to rewind. You get one more sentence.
  • No difficulty dial. The other person pushes back the way that person would. You don't get to turn them down.
  • No writing your own scenario. Twelve written ones with real pressure moves beat a blank text box.
  • No streaks, badges or practice reminders. One check-in after the real conversation, and that's it.
  • No account. Conversations stay on your phone; our server keeps none of it.

How it helps new managers (Career Coaching)

Realistic scenarios. Every counterpart has pressure moves written for them: the report who makes it about your priorities, the boss saying "just this once" for the third time. Their goal is not "the manager was nice." Some conversations end unresolved, because real ones do.

Practice and feedback. You type, you don't pick from options. The feedback opens with one verdict on your tone across the whole conversation, Firm, Too soft or Too harsh, quoting the line that shows it. Then it quotes your own words and changes one line. In the boundary scenarios, such as "Cover for Me" and "More Work, Same Team," it also checks whether you held the line, not whether the other person ended up happy.

Saying the sentence is harder than typing it. With voice input you find out whether "I'm not going to cover for you on this one" actually comes out of your mouth, and the counterpart's voice makes the pushback land with the same weight it will have in the room.

Confidence before the real thing. The prep card is three short lines written for that conversation: how to open, and then what to ask, offer, or commit to. It sits on the home screen until you walk into the room. After the real conversation, the check-in asks what was hardest and hands you the next practice for exactly that.

How we used OneSignal (Keep Them Coming Back)

OneSignal App ID: a0ab0c0b-9f01-4a0e-990c-9ecc280b853c

Unflinch sends one notification per practice, timed for after the real conversation. When the user picks the day of the real conversation, the app asks for notification permission right there (not at launch), and our Cloudflare Worker schedules a single message through the OneSignal REST API with send_after for that evening (or the next morning, the user's choice). Tapping it deep-links straight into the Debrief for that conversation. Change the date and the Worker cancels the old scheduled message before creating the new one.

We deliberately left out streaks, "come practice" nudges, and multi-step journeys. A new manager the night before a hard conversation doesn't need to be chased. One well-timed "How did it go?" brings them back at the moment the practice actually pays off, and the Debrief turns that return into the next practice.

Implementation: OneSignal iOS SDK (no notification service extension), REST API key kept server-side only, scheduling and cancellation in the Worker, deep link routed through the app's navigation stack. Verified on device via TestFlight: schedule, deliver, tap, debrief.

How we built it

SwiftUI, SwiftData, iOS 26. A Cloudflare Worker (Hono, TypeScript) holds the model, the system prompts and the limits, so the app only ever sends a scenario ID and the messages. Claude Sonnet 5 plays the counterpart with streaming; Claude Opus 5 writes the feedback as structured JSON, and the app verifies every quote against the transcript before showing it. RevenueCat for the subscription (custom SwiftUI paywall, restore, offer-code redemption through the App Store). OneSignal for the check-in. Conversations are stored on the device only; the Worker keeps no conversation text.

Voice input uses iOS 26's on-device SpeechAnalyzer: audio never leaves the phone, and nothing is sent automatically. The counterpart's voice is OpenAI TTS relayed by the Worker, one fixed voice per scenario, streamed as PCM and played sentence by sentence as the reply arrives. Only the counterpart's lines go to OpenAI, never the user's words, and the consent screen lists it as a separate recipient.

The tone verdict is part of the same structured feedback call (Claude Opus 5, JSON schema). The server drops any verdict that isn't backed by a quoted line and a turn number, and the app checks that quote against the transcript again before showing it. No new data leaves the phone.

Challenges

Making the counterpart resist the urge to agree. The AI turned out to be far more accommodating than I expected: depending on how you spoke to it, it would go along with you the way an eager-to-please person does. I spent a lot of the time tuning the prompts to make it a little stubborn on purpose, the way a real person is.

Accomplishments

Shipped in September. Started from an empty repo on September 14, submitted for review with the first in-app purchase on September 16, twelve scenarios by September 17, approved and live on September 22. In our own test conversations, the feedback was specific enough that we actually wanted to change how we said the line.

Version 1.1 added voice on September 26. Version 1.2 shipped on September 27, one day later: one verdict on tone, because the manager who is too soft needs to hear it as plainly as the one who is too harsh.

What we learned

Less feedback lands better. Everyone has their own habits in how they talk and carry themselves, so an ideal scripted response doesn't tell you what to do. A few points to change, taken from your own actual words, are what let you sort out what to pay attention to.

What's next

More conversations with your boss and with peers. Still no streaks, still no badges.

Built With

  • anthropic-claude
  • cloudflare-workers
  • hono
  • ios
  • onesignal
  • revenuecat
  • swift
  • swiftdata
  • swiftui
  • typescript
Share this project:

Updates

Submission history