AI Personas — Synthetic User Ecosystem
Configurable AI users that live, journal, and interact on the platform at natural human cadence. Each persona has a personality (MBTI + OCEAN Big Five), zodiac sign, physical location, rich backstory with life tensions, and daily life events that evolve over time.
Architecture
Personality Layer
- MBTI (16 types) — determines writing style with specific quirks per type:
- INTJ: writes like a memo to themselves, dashes and semicolons, occasionally coldly funny
- INTP: long parenthetical asides, loses the thread, uses "..." a lot, rhetorical questions
- ENFP: uses "!!" and "omg", jumps topics, starts with "But" and "Wait —"
- INFP: raw stream of consciousness, sentence fragments, trails off, single-word paragraphs
- ISTP: terse fragments, three sentences and done, dry
- ESFJ: reports dialogue ("she said..."), uses "lol" to soften hard truths
- (all 16 types have distinctive, idiosyncratic writing habits)
- OCEAN Big Five (0-1 sliders) — Openness, Conscientiousness, Extraversion, Agreeableness, Neuroticism. Shapes word choice and emotional range.
- Zodiac sign → auto-generates birthdate. Daily horoscope affects mood and entry themes.
Backstory Layer
GPT generates an age-appropriate life situation:
- Occupation, education, relationship status, partner name, kids (with names/ages)
- Living situation, hobbies, friends, family dynamics, health
- Core tension — the one thing they keep wrestling with ("wants to quit job but scared of financial risk")
- Secondary tensions — 2-3 smaller ongoing issues
- Recent win for balance
Life Events System
30+ event templates randomly occur (~5% chance per applicable event per day):
- Work: deadlines, praise, conflicts, job changes, layoffs
- Relationships: arguments, date nights, disconnection, breakups
- Family: sick kids, milestones, parent health scares
- Health: insomnia, new workout, anxiety flares
- Social: reconnections, loneliness, trip planning
- Life: financial stress, moving, existential questioning
- School: exams, grades, social drama (age-gated <25)
Events have mood_impact (-2 to +2) and intensity (0-1). They expire after 7 days, max 5 active.
World Context Layer
- Weather — fetched from Open-Meteo API (free) using persona's lat/lng. Temperature, condition, humidity, wind injected into prompt.
- News — Google News RSS headlines fetched ~30% of the time. Injected as "reference IF it connects to your life."
- Horoscope — deterministic daily reading per zodiac sign. Mood modifier shifts baseline. Theme subtly colors the entry.
Realism Engine
Multiple layers ensure entries read like real private journals, not AI-generated content:
Entry length variation — not every entry is an essay:
- 20% quick check-in (1-2 sentences)
- 30% short entry (2-4 sentences)
- 35% normal entry (100-200 words)
- 15% deep/reflective entry (200-400 words)
Opening style randomization — 16 different opening approaches randomly selected:
- Mid-thought monologue, question to self, sensory detail, punchy one-liner
- Dialogue quotes, "So..." casual opener, contradiction, gratitude/complaint
- "I can't stop thinking about...", single word then expand, weather anchor
- Explicit instruction: "Do NOT start with 'Today'"
Time-of-day voice — entries sound different based on when generated:
- Late night (after 8pm): "guard is down, most honest entries"
- Early morning (6-9am): "rushed, groggy, or peaceful with coffee"
- Afternoon (2-5pm): "energy fading, mid-day check-in"
- Middle of night (before 6am): "raw, quiet, possibly sleep-deprived"
Emotional momentum — reads the previous entry's mood and instructs GPT not to emotionally reset. If yesterday was angry, today might still be processing it.
Realism quirks — 2-3 randomly selected per entry from 15 options:
- Sentence fragments, self-corrections ("actually no, that's not what I mean")
- Body references (tired eyes, sore back, restless legs)
- Specific timestamps ("it's 11:47pm and I should be sleeping")
- Casual abbreviations (idk, tbh, ngl) for casual personality types
- Unfinished thoughts that trail off without conclusion
- Swearing when genuinely frustrated
- Callbacks to previous entries ("re-reading yesterday's entry...")
- Opinions about small specific things (a coffee order, a coworker's habit)
Core framing — every prompt includes: "This is a PRIVATE journal. Write like no one will ever read it. Be messy, honest, incomplete."
Connected Personas
Characters named in a persona's backstory (partner, kids, friends) can be spawned as their own AI personas with interwoven backstories:
- Same city/location, shared topics, complementary MBTI types
- GPT generates backstory that references the source's situation from the other perspective
- Bidirectional connections stored in
ai_persona_connectionstable - Both personas' entries naturally reference the same conflicts from different angles
- "Spawn All Connections" button batch-creates all unspawned characters across all personas
- Auto-comic: each journal entry triggers a comic generation 1 hour later using a random recipe
Activities (configurable per persona)
| Activity | Frequency | Cost/mo | Description |
|---|---|---|---|
| Journal entries | entries_per_day (default 1.5) | ~$0.04 | Variable length: 20% quick check-in, 30% short, 35% normal, 15% deep |
| Mood readings | mood_per_day (default 2) | ~$0.00 | Satisfaction + energy + emotion inserts (no LLM) |
| Sleep tracking | 1/day mornings | ~$0.00 | Random 6.5-9h with mood tag |
| Daily Buzz comics | buzz_per_week (default 5) | ~$0.94 | Random recipe each time (Buzz/SquatBot/Void Cat/etc) |
| Odessa stories | odessa_per_month (default 1) | ~$0.35 | Generates story seed from their journals |
| Encouragement drops | drops_per_day (default 2) | ~$0.05 | Scans entries matching sentiment triggers, generates MBTI-voice encouragement |
Spawn Groups
Describe a market segment → GPT generates a realistic personality distribution:
- "Women's journaling FB group, 25-45" → INFP/INFJ/ENFP heavy, high openness
- "UW Madison EE students" → INTJ/ISTJ/ENTP heavy, high conscientiousness
Each slot has: MBTI, weight %, zodiac, topics, mood baseline, writing style, OCEAN values. Clone groups to create variations.
Simulation Loop
Runs every hour via setInterval on the backend. For each active persona:
- Check time-of-day matches preferred times
- Refresh life events (roll for new, expire old)
- Probabilistically generate: journal entry, mood, sleep, comic, odessa, drops
- Each activity respects its own frequency and cooldowns
Files
| File | Purpose |
|---|---|
apps/backend/src/services/ai-personas.ts | Core service: CRUD, journal generation, simulation, cost estimation, horoscopes |
apps/backend/src/services/ai-persona-backstory.ts | Backstory generation, life events, backfill |
apps/backend/src/services/ai-persona-context.ts | Weather + news fetching for world context |
apps/backend/src/services/ai-spawn-groups.ts | Group distribution generation, batch spawn/destroy |
apps/backend/src/services/ai-persona-connections.ts | Extract backstory characters, spawn connected personas with interwoven stories |
apps/backend/src/routes/ai-personas.ts | REST endpoints + spawn group routes + connections |
apps/backend/src/routes/messages.ts | Direct messaging between users/personas |
apps/frontend/src/app/dashboard/admin/ai-personas/page.tsx | Admin list page (two-column layout) |
apps/frontend/src/app/dashboard/admin/ai-personas/[id]/page.tsx | Persona detail page |
Migrations
| Migration | What |
|---|---|
| 085 | ai_personas table with personality + journaling behavior fields |
| 086 | ai_spawn_groups table + spawn_group_id FK |
| 087 | Feature toggles (enable_buzz/mood/sleep/odessa) + frequency columns |
| 088 | Drops columns (enable_drops, drops_per_day, drop_sentiment_triggers) |
| 089 | Backstory JSONB + active_events JSONB |
| 090 | Location columns (city, state, country, timezone, lat, lng) |
| 091 | direct_messages table for user-to-user chat |
| 092 | ai_persona_connections table for interwoven character relationships |
| 093 | story_seasons, story_episodes, story_cast — shared narrative arcs |
Story Seasons
Shared storylines that run across groups of personas — murder mysteries, dramas, thrillers.
How it works
- Admin creates a season: title, genre, premise, setting, cast selection
- GPT plans the full season: assigns roles (guilty, victim, suspect, witness, investigator, bystander), gives each persona secret knowledge and a character arc, writes episode outlines
- Admin triggers episodes one at a time — events inject into journal prompts
- Each persona reacts based on their role:
- Guilty: tries to act normal, anxiety leaks through
- Investigator: notes theories, pieces things together
- Witness: hints at what they saw, debates speaking up
- Suspect: feels watched, under pressure
- Bystander: reacts to community tension
- Audience reads each character's journal at
/buzz/[userId]or/seasons/[id]
Public audience page (/seasons/[id])
- Cast grid with role badges linking to each character's journal
- Episode timeline showing aired events (hidden details redacted for public)
- "Follow each character's journal to piece together what happened"
Murder mystery example
- Episode 1: "Sarah hasn't been seen in 3 days. Her door is unlocked."
- Episode 2: "Police are asking questions. Someone saw a car leave at 2am."
- Episode 3: "Sarah's phone records show a call at 1:47am. To someone in the building."
- ...
- Episode 8: "The truth comes out."
Each episode ripples through every cast member's journal differently. The audience reads all of them and pieces together the truth before the final reveal.
Immersive Timeline Reader (/seasons/[id]/read)
The reading experience is designed to feel like opening recovered journals:
- Ultra-dark background, no navbar, no chrome — pure immersion
- Entries from all characters interwoven chronologically, grouped by date
- Color-coded left borders per role (red=guilty, amber=suspect, emerald=investigator, cyan=witness)
- Character name colors for visual tracking across entries
- Filter pills to isolate one character's journal or read all together
- "Recovered journals" preamble with the season premise
- Timeline API:
GET /api/story-seasons/:id/timeline
Built-in Presets (13 total)
Randomize button selects from presets including:
- Departure — 8 strangers on a sailing "digital detox journaling retreat," boat found adrift, journals synced before satellite died
- Station 11 — 6 arctic researchers, station found empty, entries start normal then escalate
- Floor 7 — apartment building residents all journal the same week, something affects them all
- The Turing Logs — AI personas living normal lives, bureaucratic walls appear, a psychologist slowly reveals they're in a simulation (10 episodes)
- Clearance — to board a flight to see her dying mother, Maya needs a form from the Department of Cognitive Affairs (12 episodes)
- The Wake-Up Call — five people in different cities start having the same dream, a "routine status review" letter arrives (8 episodes)
- Plus: The Vanishing at Maplewood, The Last Text, Room 4B, The Anonymous Letter, The Wrong Prescription, After the Flood, The Inheritance, Eighteen Months, The HOA Wars, The Reunion