Odessa — Personalized Story Generator
"The human field beneath the signal."
Odessa reads a user's journal entries, life map, mood history, and personal context, then generates a personalized graphic novel story — with different names, fantastical settings, but emotional dynamics that mirror the user's real patterns. The goal: help people get unstuck through entertainment that resonates with them directly.
Named after the original Odessa prototype — the breathing field that quietly stewards human adaptability.
How it works
1. Data ingestion
Odessa reads (server-side, never sent externally as raw data):
| Source | What it reads | What it's used for |
|---|---|---|
| Journal entries | Content, mood, tags, @mentions | Identifying themes, emotional patterns, relationships |
| Life Map nodes | People, projects, topics, emotions, places + edges | Mapping real people → fictional characters |
| Satisfaction/energy | Mood levels over time | Determining emotional tone of the story |
| Weekly review | Wins, open loops, mood trend | Identifying what's unresolved |
| Family members | Names, relationships, ages | Adding family dynamics to the narrative |
The lookback window is user-configurable: 7 / 14 / 30 / 90 days / all time (default: 14 days).
2. Story seed generation
A single GPT-4o-mini call with a structured system prompt that instructs the LLM to:
- Identify the dominant emotional theme — what's stuck, what's thriving, what's unresolved
- Map real people to fictional characters — change names, keep relational dynamics. The
inspired_byfield is shown privately to the user. - Choose a metaphorical setting — a fantastical world that mirrors the emotional landscape. Steampunk workshop for a builder. Underwater city for someone feeling submerged. A returning-light world for someone processing grief.
- Design a 3-act arc — Act 1 mirrors the current state. Act 2 explores what happens if the protagonist leans into the fear. Act 3 offers a resolution the user might not have considered.
- Generate the art style — matched to the emotional tone. Dark crosshatch for heavy themes. Warm watercolor for grief. Neon for excitement.
3. Story seed structure
interface StorySeed {
title: string
theme: string // "The tension between ambition and rest"
genre: string // "Steampunk adventure"
art_style: string // DALL-E style prompt
setting: string // Metaphorical world description
tone: string // Narrative voice
characters: Array<{
name: string // Fictional name
inspired_by: string // "Mapped from: Owen (your son)"
visual_description: string // For DALL-E character consistency
role_in_story: string
}>
narrative_arc: {
act1: string // Setup — mirrors user's current state
act2: string // Complication — leaning into the fear
act3: string // Resolution — a new perspective
}
opening_prompt: string // First scene to kick off the chat
resonance_note: string // Why this story (addressed to user)
}
4. Flow: seed → graphic novel
- User visits
/dashboard/odessa - Optionally sets a focus ("I can't stop thinking about...") and lookback window
- Clicks "Generate my story seed" → sees the seed card with characters, arc, resonance note
- Clicks "Start this story →" → system creates a
graphic_novelnotebook pre-configured with the seed's art style, characters, setting, tone, and opening conversation - User lands in the graphic novel editor with the opening prompt pre-loaded
- Co-development begins through the existing chat → panels → DALL-E pipeline
Architecture
User clicks "Generate"
↓
POST /api/odessa/generate-seed
↓
odessa.ts gatherUserContext()
→ fetches journal entries, life map, satisfaction, weekly review, family
↓
odessa.ts generateStorySeed()
→ GPT-4o-mini with structured JSON output
→ returns StorySeed
↓
User reviews the seed card
↓
POST /api/odessa/create-story
→ creates a graphic_novel notebook with the seed as config
→ returns notebook_id
↓
User redirected to /dashboard/entries/new?notebook={id}
→ GraphicNovelEditor opens with opening prompt pre-loaded
→ co-development begins
Privacy
- Odessa reads journal data server-side. Raw journal content is never sent to external services — the GPT call sends only excerpts (first 300 chars per entry) + mood + tags + mentions.
- The StorySeed is the only artifact. It contains no real names (only
inspired_byhints shown privately to the user). - The graphic novel itself (panels, images, narration) is stored as standard journal entries in the user's own notebook.
- Deleting the notebook deletes the story. No external copies.
Story lengths
| Length | Pages | Panels | Time | Scene structure |
|---|---|---|---|---|
| Flash (default) | 3 | ~10 | 2-4 min | 1 page per act |
| Short Story | 9 | ~30 | 8-15 min | 3 scenes per act (deepen world → escalate → climax → resolution) |
| Novel | — | — | — | Coming soon (will require job queue for 30+ minute generation) |
Short Story sub-prompts are structured for proper narrative pacing: Act 1 deepens the world, Act 2 escalates through failure, Act 3 resolves with an image echoing the opening.
Endpoints
| Endpoint | Auth | Description |
|---|---|---|
POST /api/odessa/generate-seed | Required | Reads user data, returns a StorySeed. Accepts { focus?, lookback_days? } |
POST /api/odessa/create-story | Required | Takes a StorySeed, creates a graphic_novel notebook, returns notebook_id |
POST /api/odessa/generate-full-story | Required | Takes a StorySeed + { length: 'flash' | 'short_story' }, creates notebook, auto-generates all pages with DALL-E illustrations |
POST /api/odessa/next-episode | Required | Generates next episode for an existing Odessa story. Reads journal delta since last episode, computes character stats, feeds into narrative engine |
POST /api/odessa/resolve-branch | Required | Records user's branch choice at a narrative decision point |
GET /api/odessa/character-stats | Required | Returns live CharacterStats (energy, resilience, connection, clarity, momentum) derived from 14-day activity window |
GET /api/odessa/story-state/:id | Required | Returns persisted story state, character stats, and seed for a notebook |
Files
| File | Purpose |
|---|---|
apps/backend/src/services/odessa.ts | Analysis engine: data ingestion + GPT story seed generation |
apps/backend/src/routes/odessa.ts | REST endpoints |
apps/frontend/src/app/dashboard/odessa/page.tsx | Dashboard launch page |
apps/frontend/src/app/odessa/page.tsx | Public landing page |
apps/frontend/src/components/notebooks/CharacterStatsCard.tsx | Character stats bar display (notebook page + Odessa dashboard) |
Character stats
Character stats mirror the user's real-life patterns into their story character's attributes. Computed from a 14-day rolling window:
| Stat | Source | Interpretation |
|---|---|---|
| Energy (1-10) | satisfaction_quick_values.energy_level average | High = character is vibrant/proactive; low = drained/slow |
| Resilience (1-10) | family_routine_checkins done rate | High = recovers quickly; low = fragile, overwhelmed |
| Connection (1-10) | Unique @mentions across journal entries | High = rich relationships/allies; low = isolation |
| Clarity (1-10) | Mood variance (lower = higher clarity) | High = sees path ahead; low = fog/confusion |
| Momentum (1-10) | user_tasks completion rate | High = things are moving; low = stuck |
Stats are injected into the generateNextEpisode() GPT system prompt with behavioral descriptors. When stats change between episodes, the delta is noted so GPT can narrate the shift (e.g., "energy rose from 3 to 7 — the character gains strength"). Stats persist on StoryState.character_stats between episodes.
Connection to the broader platform
Odessa is the narrative layer of HiveJournal's "Free the Energy" philosophy:
- The journal is where you measure your friction (what's draining energy, what's stuck)
- JQ is the companion that helps you process in real-time
- The Life Map is the graph of everything you care about
- Odessa is where all of that becomes a story — because sometimes the only way to see a pattern is to watch a character live through it
The name echoes the original Odessa prototype: "a breathing field — a structure for those who rebuild, remember, and reweave." Now it rebuilds through narrative.