State Tides is a lightweight Next.js prototype for showing that a mental or emotional state is not continuous over time.
The app takes a short fragmented note, looks for similar past entries in a local longitudinal dataset, and presents:
- a calm
Analysisview with structured state inference - related past fragments
- a dot-based timeline with visible gaps
- a lightweight
Next Actionreflection flow showing that responses vary
The product message is evidence-based rather than advisory:
This state appeared before, but it was not continuous.
- Next.js 15
- TypeScript
- React 19
- local JSON demo data
- Claude API integration with local fallback
When a user submits a short note, the app:
- sends the text to
/api/classify-state - infers a structured internal state record
- compares it against known state nodes
- uses Claude if available, otherwise falls back to local heuristics
- finds similar past entries from local demo data
- visualizes recurrence and discontinuity on a timeline
- lets the user record a lightweight
next_action - shows that past responses were not always the same
npm installCopy .env.example to .env.local and add your own Anthropic API key:
ANTHROPIC_API_KEY=your-real-anthropic-api-key
ANTHROPIC_MODEL=claude-sonnet-4-20250514Important notes:
.env.exampleis only a template.env.localis the file Next.js actually reads during local development- do not commit
.env.local
npm run devThen open:
http://127.0.0.1:3000If you want the same host/port used during local testing in this repo:
npm run dev -- --hostname 127.0.0.1 --port 3002The prototype is already wired to call Claude through:
app/api/classify-state/route.ts
Claude is used only as the semantic layer. It helps:
- infer strict JSON state records with:
situationautomatic_thoughtemotion_labelsemotion_intensitybehavior
- compare a new note against existing state nodes
- score similarity to multiple states
- decide whether the note is novel enough to create a new state
- If
ANTHROPIC_API_KEYis present and the account has available credits, the app will use Claude. - If the API key is missing, invalid, rate-limited, or out of credits, the app automatically falls back to the local heuristic implementation.
This means the prototype still works end-to-end without external API availability.
The app keeps a hidden structured state schema behind the UI. That schema includes fields such as:
situationautomatic_thoughtemotion_labelsemotion_intensitybehavioralternative_framingtagssimilar_statesis_novelnext_action
This structure is used internally for inference and comparison. It is not exposed as a CBT worksheet UI.
The repo uses local anonymized synthetic data for the demo:
data/journal-entries.jsondata/state-nodes.json
Note:
data/state-nodes.jsoncan change locally during runtime when a note is classified as novel- for clean demos or commits, restore that file before committing if you do not want runtime-generated state nodes in git
The dataset is designed to show:
- recurrence
- gaps
- discontinuity
- variation in next actions
npm run dev
npm run build
npm testapp/page.tsx: main prototype UIapp/api/classify-state/route.ts: Claude/fallback classification endpointlib/state-classification.ts: internal state inference and parsinglib/state-tides-service.ts: similarity and timeline helperslib/matching.ts: local similarity matchingtests/matching.test.ts: lightweight test coverage
- This is not a therapy app.
- It does not recommend what the user should do.
- It does not rank behaviors.
- The main insight is recurrence with interruption, not continuity.