Reposait
Apr 2026 - present | Private alphaA CBT-grounded journaling app with an AI coach that asks instead of tells.
- Next.js 16
- React 19
- TypeScript
- Supabase + RLS
- Vercel AI SDK
- Claude Sonnet
- Vitest
Reposait comes from the French reposer: to rest, to set something down. You write two or three times a day, and an AI coach answers every entry with a short reflection and exactly one Socratic question. It never names a technique and never diagnoses. I am the builder and the first user.
why_i_built_it
Most people who could benefit from structured reflection never start, or stop within a week. I was one of them. I knew my own patterns but had no practice for working through them, and therapy carries real cost and real activation energy.
- The blank page asks too much. A warm, specific prompt at the right time of day is what gets you writing.
- Writing into a void stops working by day three. A response that takes the entry seriously is the feedback loop that makes the habit stick.
- Existing tools are too clinical or too shallow. Workbooks read like textbooks, and mood trackers flatten a day into a number. I wanted the technique to be invisible: CBT, ACT, and positive psychology in practice, never in vocabulary.
- I wanted to learn agentic engineering on something real. A product I use every day, holding private writing, forces the decisions a demo never does: data boundaries, latency, cost, and prompt quality over time.
how_i_built_it
Next.js 16 App Router on Vercel, Supabase for auth and Postgres, and Claude through the Vercel AI SDK. Sixteen migrations, 88 test files, and a decision log that records why, not just what.
- Row-level security is the security boundary. Application code does not filter user data; Postgres does. The service-role key appears only where the server writes on a user's behalf, and every use carries a comment saying why.
- One provider seam. Every model call goes through
lib/ai/provider.ts, the only file that imports the Anthropic SDK. Swapping a model or a provider is a one-file change. - Structured output over parsing. Coaching comes back through
generateObjectagainst a Zod schema, which replaced a brittle 40-line JSON parser. - The user's local date, not UTC. Entries group by a date computed in the user's time zone, because an entry written at 10pm in Chicago belongs to today. Getting this wrong was the first real bug.
- Rhythm is a display filter, never a data filter. Users pick two or three sessions a day, and switching never drops an entry.
building_with_claude_code
Claude Code was the primary implementer. My job moved to defining the problem, setting constraints, and verifying the result, and what made that work was treating the agent's context as an engineering artifact.
- CLAUDE.md is the contract. Architecture rules, naming conventions, scope guards, and known mistakes live in one file every session reads first. When the agent drifts, the fix is usually a sentence there, not a correction in chat.
- Memory carries feedback across sessions. Two rules I set early still hold: tests are written alongside code, not after, and schema designs are reviewed before any SQL is written. Both exist because I caught the agent skipping them once.
- Specs before code, UAT after every feature. Each feature starts as a GitHub issue with acceptance criteria and ends with me clicking through it in a browser. Green tests prove correctness in isolation; the browser proves it works.
- A decision log the next session can trust. Every reversed decision is recorded with its reason, so the agent does not re-propose an idea that was already rejected.
- Multi-agent review, then delegation. Before beta I ran a 62-agent adversarial review across security, one-way doors, duplication, and dead code. 51 findings survived verification, and a skeptic pass talked an initial six "high" findings down to zero. The fixes became a wave-based plan of self-contained briefs, each sized for one context window, sequenced by file contention rather than by topic.
agents_in_production
Reposait runs coaching, summarization, pattern detection, and a tool-using goal coach. Each one taught something different about putting a model in front of real users.
- Context engineering beats a bigger context window. Coaching first sent 14 days of raw entries with every call. Now a background agent rewrites a therapist-style summary every seven entries, and coaching assembles three layers: that summary, a recurring-themes index, and the two latest entries truncated to 500 characters. Input tokens fell about 40% and the questions got sharper.
- Agents stay off the critical path. Summarization and pattern detection run through Next.js
after()once the entry is saved. A failure is logged and never blocks the write. - Not everything needs a model. The morning prompt used to be generated and added two seconds to the first screen of the day. A static "Good morning, Ted. What's on your mind?" did better.
- Give the agent an action, not a field. The goal coach first returned a
settledFieldkey in structured output, and the model left it empty while asking one more question. Rebuilt as a tool-using agent withsuggest_field,offer_options, andcomplete_goal, it had a forcing function, and the form started filling. - Propose, don't commit. The coach suggests a starting value for each goal field and the user accepts or edits it. Nothing the model writes becomes the user's without their hand on it.
- Probe live before wiring UI. A live run of the tool-using coach caught it calling tools and returning no text, which would have rendered an empty bubble every turn. One prompt line and a fallback reply fixed it before any UI depended on it.
- Guardrails are versioned like code. One question, never name a technique, warmth without praise. Each prompt exports a version string, so a change in coaching quality can be traced to the prompt change behind it.