Seuil / Independent product / iOS
Practice with something to say.
French practice for TEF and TCF, with adaptive sessions and feedback across speaking, writing, reading, and listening.
Built with
- Application
- TypeScript
- React Native
- Expo
- Expo Router
- State & review
- Zustand
- FSRS / ts-fsrs
- AsyncStorage
- Backend
- Supabase
- PostgreSQL
- Supabase Auth
- Supabase Edge Functions
- AI & speech
- Anthropic Claude API
- OpenAI API
- Expo AV
- Device features
- Expo Notifications
- Testing & release
- Node.js test runner
- tsx
- EAS Build
- EAS Submit

Original App Store screenshots.
My contribution
I built the app, including adaptive practice, speaking interactions, sentence-level feedback, and the iOS release.
Under the surface
The engineering.
A learner repeating a phrase after a hint has demonstrated something different from using it independently the next day. I modeled that distinction explicitly, then used it to decide what the tutor should ask next.
Capture an attempt
Record the utterance, target ability, and support level.
Validate feedback
Check assessment identity, outcome, and evidence fields.
Update ability
Store attempts separately from the derived readiness state.
Plan the next turn
Rank discovery, repair, retest, or harder practice.
Decision / 01
An encouraging AI reply cannot be the progress model.
A successful answer with a prompt should not count as independent mastery. Repeating the same scenario immediately is weak evidence that a learner can use the language elsewhere.
The learning model records outcome, support level, scenario, speaker, and time for each attempt. The readiness rule requires an unassisted success following another unassisted success at least 12 hours earlier, in a different scenario. Other successes schedule a retest; unsuccessful attempts stay in learning. A user/session/turn uniqueness constraint prevents storing the same turn twice.
The rule makes readiness inspectable, but the 12-hour interval is a product heuristic, not a validated prediction of exam performance. The app still depends on the quality of the assessment feeding that rule.
Decision / 02
Keep the next-step decision outside the language model.
A conversational tutor can dwell on one mistake or keep teaching familiar material. The next exercise needs to reflect the learner’s history and placement.
A TypeScript planner ranks abilities using due retests, recent errors, support levels, response times, and placement. It gives overdue retests priority, applies a six-hour cooldown to immediate repair, and can unlock harder material from fast independent responses. It returns a mode and a reason, making the recommendation inspectable and testable with a fixed clock.
Explicit weights and thresholds are easier to reason about, but they need tuning as learning evidence accumulates. The planner tests cover retest priority, repair cooldown, placement, and advancement without claiming measured learning gains.
Decision / 03
Treat feedback as structured input to the application.
The model can return well-formed text that refers to the wrong ability, invents a construction identifier, or keeps asking the learner to repeat.
The assessment normalizer requires the active ability ID, a recognized outcome, and a nonempty evidence field. Construction IDs must belong to the supplied target set, and confidence is clamped to a valid range. Training context caps repair attempts at two; the tutor instructions then ask it to move on while preserving the unresolved outcome.
These checks constrain the shape and target of the assessment. They do not prove that the quoted evidence is correct or that a linguistic judgment is accurate. That distinction matters when feedback changes a learner’s next session.
Decision / 04
Voice interaction is a sequence of states.
Recording, transcription, generation, and playback finish at different times. A second tap or a response arriving after the conversation ends must not start another turn.
The conversation hook separates ready, recording, transcribing, thinking, speaking, and failed states. Refs guard recording startup and processing; ended/unmounted checks discard late results. Metering supports silence-based stopping, recordings are capped at 20 seconds, and empty or known suspicious transcripts return the learner to a retry state.
A staged recording pipeline is easier to expose and recover in the interface, but the learner waits for transcription and generation between turns. Meter thresholds also depend on the speaker and environment.
Edge cases
What happens when…
- A learner succeeds with a hint
- Schedule another attempt; assisted success alone does not satisfy the readiness rule.
- An assessment names a different ability
- Reject that assessment instead of attaching it to the active target.
- A learner struggles, then immediately returns
- Deprioritize immediate repair during the cooldown so another ability can be practiced.
Axlow
Payer-policy search that connects natural-language questions with relevant documentation.