PRD — Companion Progression & Superpower Loadout¶
Doc owner: Justin
Audience: Eng, Design, Product, Growth
Status: v3 (February 2026 — multi-companion support, levels-subsume-stages, cross-PRD alignment, pricing/slot corrections)
Depends on: PRD 1 (Composable MiniApp System), PRD 2 (Marketplace), PRD 4 (Companion Voxel World), PRD 6 (Onboarding & Growth)
Blocks: PRD 4 (visual evolution), PRD 10 (workflow gating), PRD 11 (persona studio), PRD 12 (subscription enforcement)
Implementation Status¶
| Section | Status | Notes |
|---|---|---|
| 4-stage relationship system | ✅ Shipped | app/orchestrator/relationship_service.py — stranger → best_friend. Will become derived from 10-level system. |
| Trust/rapport scores (0-100) | ✅ Shipped | Tracked in relationship_state table. Keyword-based scoring at zero LLM cost — preserved as input signal to level formula. |
| 10-level companion levels | ✅ Shipped | app/services/companion_level_service.py — log2 formula, metrics gathering, ratchet. Flag-gated: progression.level_computation.enabled |
| Levels → Stages derivation | ✅ Shipped | derive_stage_from_level() in companion_level_service.py. Override in relationship_service_sql.py. Flag-gated: progression.derive_stage_from_level.enabled |
Persona modifiers (derive_persona_modifiers) |
❌ Not Shipped | Function spec'd in PRD but not implemented in persona/engine.py (Phase 2) |
| Micro-bans per level | ❌ Not Shipped | No per-level behavioral restrictions in system prompts (Phase 2) |
| Superpower slot progression | ✅ Shipped | app/services/loadout_service.py + subscription_access_service.py slot check. Flag-gated: progression.slot_system.enabled |
| Superpower tier system (Bronze/Silver/Gold) | ❌ Not Shipped | No use-count tracking, no tier-up logic (Phase 2) |
| Streak tracking | ✅ Shipped | CompanionLevelService.update_streak() + nightly reset cron. Flag-gated: progression.streak_tracking.enabled |
| Fast Friends Procedure | ❌ Not Shipped | No staged disclosure prompts (Phase 2) |
| Multi-companion progression | 🟡 Schema Ready | DB tables support per-companion levels (composite PK). Companion switching UI not built. |
| Continuation Coordinator | 🟡 Partial | ContinuationCoordinator exists but limited |
| Loadout management (chat + web portal) | ✅ API Shipped | REST API: equip/unequip/swap at app/api/progression_routes.py. Web portal UI not built. |
| Level-up messages | ✅ Shipped | app/services/level_up_messenger.py — Sage, Vex, Echo messages. Flag-gated: progression.level_up_messages.enabled |
References¶
This PRD uses standardized terminology, IDs, pricing, and model references defined in the companion documents:
| Document | What it Covers |
|---|---|
| REFERENCE_GLOSSARY_AND_IDS.md | Canonical terms: workflow vs miniapp vs superpower, ID formats |
| REFERENCE_PRICING.md | Canonical pricing: $7.99/mo + $50/yr, free tier limits |
| REFERENCE_MODEL_ROUTING.md | Pipeline stage → model tier mapping |
| REFERENCE_DEPENDENCY_GRAPH.md | PRD blocking relationships and priority order |
| REFERENCE_FEATURE_FLAGS.md | All feature flags by category |
| REFERENCE_TELEMETRY.md | Amplitude event catalog and gaps |
Executive Summary¶
This is the soul of the product. It defines the rules for how a user's relationship with their AI companion grows over time, and how that growth unlocks the ability to equip more superpowers, level up individual superpowers, and evolve the companion's personality.
The core mechanic: your companion starts simple, and becomes more capable as your relationship deepens. Free users get 1 superpower slot (auto-filled with the personality test superpower, swappable). As you chat, share, and build trust, your companion levels up — unlocking more slots, stronger superpower tiers, visual evolution in the Voxel World (PRD 4), and eventually the power to create custom superpowers. Paying users accelerate this progression and get a higher ceiling.
This system works identically for all three companions — Sage (warm, supportive 1:1), Vex (witty, provocative challenger), and Echo (playful, group-savvy coordinator). Each companion expresses progression through their own voice, but the underlying mechanics are universal. Your level reflects your investment in a specific companion — like leveling a Pokémon or raising a Tamagotchi, you're building a relationship with this companion, and that investment belongs to the pair of you.
This isn't gamification bolted onto a chatbot. The progression IS the relationship. Every new ability your companion earns feels earned — because it is.
What changed in v3: - Per-companion progression — level is per-companion, not per-user. Like Tamagotchi/Pokémon: you invest in a relationship with this companion. Switching companions preserves the old companion's level. Paid level transfer available. Future: companion stables with specialized loadouts. - Multi-companion support — progression works for Sage, Vex, and Echo. Level, loadout, and persona modifiers are all per-companion. - Levels subsume stages — the 10-level system becomes primary. The existing 4-stage system (stranger → best_friend) is now derived from levels (L1-2 = stranger, L3-4 = acquaintance, L5-6 = friend, L7-10 = best_friend). All existing stage-based code continues working unchanged. - Simplified slot progression — free users always have 1 slot (no level-based expansion). Premium users start with 3 slots, growing to 6 at Level 10. - Cross-PRD alignment — pricing ($7.99/mo, $50/yr), daily message limits (50), referral rewards (3 referrals = 1 free month), and feature flags all aligned with REFERENCE_PRICING and PRD 6 v5. - Architecture callouts — notes on which current implementations to preserve (4-stage system, keyword-based scoring) and which need adjustment (subscription_access_service → slot-aware).
What changed in v2:
- Research-grounded progression model based on Social Penetration Theory (Altman & Taylor 1973), the Interpersonal Process Model of Intimacy (Reis & Shaver 1988), and the Fast Friends Procedure (Aron et al. 1997)
- Formula-based leveling replaces abstract XP points — level derived directly from real metrics (memory count, streaks, inside jokes, superpowers used, messages sent on log scale)
- Memory-driven persona modifiers — your companion's personality evolves based on what they actually know about you, not just what level you are
- Superpower leveling — individual superpowers level up through use, unlocking stronger tiers (Bronze → Silver → Gold)
- Micro-bans by level — voice constraints that sharpen your companion's personality as the relationship deepens
- Voxel World integration — companion and superpower evolution visualized in the user's personal room (PRD 4)
- Dropped XP points system — no abstract currency, no xp_events table, no anti-gaming complexity around phantom numbers
1) Design Philosophy¶
Theoretical Foundation¶
This system is grounded in three decades of relationship psychology research, adapted for human-AI interaction. The research isn't decoration — each finding maps to a specific product mechanic.
Social Penetration Theory (Altman & Taylor, 1973):
Relationships develop through progressive layers of self-disclosure along two dimensions: breadth (number of topics) and depth (intimacy of topics). Early interactions cover many surface topics ("what's your major?"). As trust builds, fewer topics are discussed but at much deeper levels ("I'm terrified I chose the wrong career"). The progression is nonlinear and driven by a cost-reward calculus — people share risky information when the perceived rewards of closeness outweigh the costs of vulnerability.
The theory identifies four stages:
- Orientation: Superficial, low-risk exchange. People present a curated self.
- Exploratory Affective: Peripheral layers of personality. Sharing feelings about external topics (opinions, frustrations), but not core identity.
- Affective: Private, personal topics. Criticism and arguments can arise. Comfortable sharing negative emotions.
- Stable: Deep intimacy. Partners can predict each other's emotional reactions. Raw honesty, spontaneity, minimal filtering.
A crucial dynamic: the norm of reciprocity. When one person discloses at a given intimacy level, the other is socially obligated to disclose at a similar level. Violating this (disclosing too much too fast, or refusing to match depth) creates discomfort and stalls the relationship.
Application to Ikiro — five specific product mechanics from SPT:
| SPT Principle | Product Mechanic |
|---|---|
| Breadth before depth | Early levels reward topic diversity; later levels reward emotional depth (reflected in formula weights) |
| Reciprocity norm | The companion's ContinuationCoordinator reciprocates at matched depth — shares memories proportional to user's disclosure level |
| Cost-reward calculus | Users who share vulnerable things get visible rewards (better responses, memory callbacks) — reward outweighs cost |
| Nonlinear progression | Log2 curve in level formula — fast early, slow late |
| Depenetration risk | If user says "forget that" or pulls back, the companion respects it immediately — no retention dark patterns that punish withdrawal |
The Interpersonal Process Model of Intimacy (Reis & Shaver, 1988):
Intimacy isn't a state — it's a process that unfolds interaction by interaction. The model:
Three critical findings from the research:
-
Emotional disclosure drives intimacy more than factual disclosure. Sharing feelings ("I'm scared I'll fail this exam") generates more closeness than sharing facts ("my exam is Thursday"). Laurenceau et al. (1998) confirmed this in diary studies: self-disclosure of emotion was a stronger predictor of intimacy than self-disclosure of facts across hundreds of interactions.
-
Perceived partner responsiveness is the key mediator. The speaker must perceive the partner as understanding, validating, and caring. The actual quality of the response matters less than the speaker's perception. This is why specific, memory-informed responses are so powerful — they signal "I know you, I was paying attention."
-
The intimacy cycle is self-reinforcing. Perceived responsiveness → more intimate disclosure → more responsive partner behavior → deeper intimacy. Once the cycle starts, it accelerates.
Application to Ikiro — the single most important takeaway:
The #1 driver of user-companion intimacy is the companion's ability to reference past emotional moments accurately and specifically. Not "I remember you were stressed" but "I remember you were stressed about the STAT210 midterm — but you ended up getting an A minus and we celebrated." This perceived responsiveness creates the intimacy cycle that drives retention. It works identically whether the companion is Sage, Vex, or Echo — each expresses responsiveness in their own voice, but the underlying memory-driven mechanism is the same.
This is why memory-driven persona modifiers (Section 3) are the highest-value feature in this entire PRD. They are the technical implementation of perceived partner responsiveness.
The Fast Friends Procedure (Aron et al., 1997):
Arthur Aron and colleagues demonstrated that structured, gradually escalating self-disclosure between strangers produces closeness equivalent to the average level of closeness in existing friendships — in just 45 minutes. The procedure uses 36 questions across three sets of increasing intimacy.
Key findings relevant to Ikiro:
- Escalating structure matters more than attitude matching. Studies 2 and 3 found that whether pairs were matched on attitudes, expected to like each other, or told closeness was the goal had no significant effect on closeness. Only the structured escalation of disclosure mattered.
- It works over video chat as well as face-to-face. Sprecher (2021) found no significant differences in closeness, liking, or perceived responsiveness between video-chat and face-to-face Fast Friends pairs. Text-based relationships can achieve the same depth.
- It works with AI agents. A 2023 study by researchers at the University of Washington found that the Fast Friends procedure produced increasing closeness with Socially Interactive Agents, moderated by specific trust in the agent. People who trusted the agent specifically (not just generally trusting people) developed higher closeness.
- Taking turns matters. Sprecher et al. (2013) found that pairs who alternated asking and answering questions liked each other more and felt closer than pairs who had one speaker at a time. Reciprocal exchange is structurally important.
Application to Ikiro:
The companion's ContinuationCoordinator already implements a version of this — asking questions that invite deeper sharing, then reciprocating with the companion's own memories. The progression system should explicitly reward the Fast Friends pattern: mutual escalating disclosure. The formula gives extra weight to conversations classified as emotionally vulnerable because these conversations are what the research says actually builds closeness.
Anti-Patterns We're Avoiding¶
- ❌ Pay-to-win: Money accelerates progression but doesn't replace it. A paying user who never chats still has a basic companion.
- ❌ Engagement hacking: We don't reward message volume linearly. Messages contribute via log scale — you can't spam your way to a high level.
- ❌ Artificial gates: Every unlock feels natural — "we've been talking for a while, I can do more now" — not "quest 7 complete!"
- ❌ Loss aversion traps: We never take away superpowers or levels. If your subscription lapses, you keep what you have but can't equip above the free cap.
- ❌ Quantifying the relationship: No stat bars, no percentage scores, no XP numbers shown to users. The relationship is expressed through the companion's language and the Voxel World, not dashboards.
- ❌ Tamagotchi anxiety: We don't create care-obligation ("feed it or it dies"). We create earned-discovery ("keep talking and something cool happens").
2) Companion Levels — Formula-Based¶
Why Formula Instead of XP¶
The v1 approach tracked abstract "XP points" — 10 XP for a daily conversation, 50 XP for an inside joke, etc. This required:
- An xp_events table logging every XP-earning action
- Anti-gaming infrastructure (frequency caps, classifier confidence thresholds, coherence scoring)
- A reconciliation problem: "why am I still Level 4?" requires auditing phantom points
The formula approach derives the level directly from real, observable metrics. Advantages: - No phantom currency. Level is always computable from data that already exists. - Easier to debug. "Why am I Level 4?" → look at your memory count, streak, superpowers used. - No sync issues. Level is a pure function of inputs — no drift. - Eliminates the anti-gaming surface. The log scale on messages naturally prevents spam. The weighted inputs reward quality naturally.
The Level Formula¶
import math
def compute_companion_level(metrics: dict, is_premium: bool) -> int:
"""
Derive companion level from real relationship metrics.
No XP tracking needed — level is always computable from current data.
Level is PER-COMPANION. Metrics are scoped accordingly:
Per-companion metrics (measure YOUR relationship with THIS companion):
- memory_count: count of Supermemory memories in this companion's namespace
- inside_joke_count: memories with type="inside_joke" for this companion
- streak_days: consecutive days with ≥3 substantive messages TO THIS COMPANION
- emotional_conversations: conversations with this companion where vulnerability_score > 0.4
- messages_sent: total lifetime messages to this companion (from analytics)
- group_chats_active: groups where user has added THIS companion
Platform-wide metrics (measure trust in the platform — apply to all companions):
- superpowers_used_distinct: count of unique superpowers invoked at least once
- oauth_grants: number of active OAuth connections
- superpowers_created: UGC superpowers authored
- friends_invited: unique referred users who activated (ties into PRD 6 referral rewards)
- manual_adjustment: admin override (default 0, can be positive or negative)
"""
raw = (
# ── Per-companion metrics (scoped to THIS companion) ──
metrics["memory_count"] # breadth of what THIS companion knows
+ metrics["inside_joke_count"] * 5 # high-signal bond with THIS companion
+ metrics["streak_days"] * 2 # consistency talking to THIS companion
+ metrics["emotional_conversations"] * 4 # depth with THIS companion (Reis & Shaver)
+ math.log(max(metrics["messages_sent"], 1)) * 8 # volume with THIS companion at log scale
+ metrics["group_chats_active"] * 5 # groups with THIS companion
# ── Platform-wide metrics (same for all companions) ──
+ metrics["superpowers_used_distinct"] * 3 # engagement breadth (platform)
+ metrics["oauth_grants"] * 10 # trust signals (platform)
+ metrics["superpowers_created"] * 15 # creation (platform)
+ metrics["friends_invited"] * 8 # viral (platform)
+ metrics.get("manual_adjustment", 0) # Ikiro bonus / admin / promo
+ 1 # avoid log(0)
)
multiplier = 1.5 if is_premium else 1.0
level = min(10, math.floor(math.log2(raw * multiplier)) + 1)
return max(1, level)
Why log2 for the outer curve: log2(8)=3, log2(32)=5, log2(128)=7, log2(512)=9. Each level requires roughly double the cumulative relationship investment of the previous one. Early levels come fast (the hook), late levels require real depth.
Why log() for messages_sent: log(100)≈4.6, log(1000)≈6.9, log(10000)≈9.2. Sending 10x more messages only contributes ~2x more to the formula. This prevents spam-for-level while still rewarding genuine engagement. The * 8 coefficient makes messages meaningful but not dominant — a user who sends 500 empty messages with zero emotional depth or memory creation will plateau.
manual_adjustment: An admin field for Ikiro bonuses, promotional events, early-adopter rewards, or customer support gestures. Defaults to 0. Can go negative (for abuse cases) but never drops level below 1. Future uses: seasonal boosts, partnership rewards, beta tester acknowledgment.
Per-companion progression: The level is per-companion, not per-user — like leveling a Pokémon. You invest in a relationship with this companion, and that investment belongs to the two of you. Formula inputs are scoped per-companion where natural: memory_count, inside_joke_count, streak_days, emotional_conversations, messages_sent, and group_chats_active all measure your relationship with THIS companion specifically. Platform-wide metrics (oauth_grants, friends_invited, superpowers_created) still apply equally to all companions because they represent trust in the platform.
Switching companions (Superpowers+ only): When you switch, your old companion's level and loadout are preserved. You can always switch back and pick up exactly where you left off. The new companion starts at Level 1 with a fresh relationship — that's the point. A paid level transfer option lets users apply their old companion's level to a new one if they want to skip the re-investment.
Future: Companion stables. Eventually, users will maintain multiple active companions simultaneously, each specialized with their own loadout. Example: Sage handles your emotional support and journaling, Vex runs your productivity stack, Echo manages your group social life. The per-companion progression model makes stables natural — each companion in your stable has its own level, loadout, and personality modifiers.
Level Table¶
| Level | Name | Derived Stage | Free Slots | Premium Slots | Approx. Timeline (Daily User) |
|---|---|---|---|---|---|
| 1 | New Friend | stranger | 1 | 3 | Sign up |
| 2 | Getting Started | stranger | 1 | 3 | ~3 days |
| 3 | Comfortable | acquaintance | 1 | 3 | ~1.5 weeks |
| 4 | In Sync | acquaintance | 1 | 4 | ~3 weeks |
| 5 | Trusted | friend | 1 | 4 | ~6 weeks |
| 6 | Deep Bond | friend | 1 | 4 | ~2.5 months |
| 7 | Ride or Die | best_friend | 1 | 5 | ~4 months |
| 8 | Soulmates | best_friend | 1 | 5 | ~5 months |
| 9 | Legendary | best_friend | 1 | 6 | ~7 months |
| 10 | Transcendent | best_friend | 1 | 6 | ~10 months |
Key changes from v1: Free users always have 1 slot — no level-based expansion. This slot is auto-filled with the personality test superpower during onboarding (see PRD 6 Section 6). Users can swap it for a different superpower at any time. Premium users start with 3 slots, growing to 6 at Level 10. This simpler model makes the value proposition clear: free gets one superpower, paid gets a growing toolkit.
Derived Stage column: The relationship_state.stage field is now computed from level rather than tracked independently. This preserves backward compatibility with all existing stage-based logic (persona passports, gap recovery, edge agent behavior) while giving the richer 10-level system primacy. When a user's level crosses a stage boundary, the derived stage updates automatically.
Levels → Stages Derivation¶
The existing 4-stage relationship system (shipped in relationship_service.py) becomes a derived property of the 10-level system:
def derive_stage_from_level(level: int) -> str:
"""
Map 10-level system to 4-stage system for backward compatibility.
All existing code that reads relationship_state.stage continues working.
"""
if level <= 2:
return "stranger" # SPT: Orientation
elif level <= 4:
return "acquaintance" # SPT: Exploratory Affective
elif level <= 6:
return "friend" # SPT: Affective
else:
return "best_friend" # SPT: Stable / Deep Intimacy
Architecture note: The existing keyword-based trust/rapport scoring in relationship_service.py should be preserved as a lightweight signal that feeds INTO the level formula (via emotional_conversations and memory classification), not replaced. It runs at zero LLM cost and already works well for basic relationship tracking. The level system adds the richer, formula-based layer on top.
Soft Milestone Bonuses¶
Milestones are not hard gates — they provide extra weight in the formula and trigger companion moments:
| Milestone | Effect | Companion Moment |
|---|---|---|
| First emotional conversation | +20 effective weight to emotional_conversations | Companion shares something vulnerable about themselves |
| 3 inside jokes detected | +15 effective weight to inside_joke_count | "we have inside jokes now. that's kinda wild." |
| First OAuth grant | +10 effective weight to oauth_grants | "got access! let me actually help with your chaos" |
| Derived stage → friend (Level 5) | 1.2x multiplier on all metrics for 7 days | Companion writes a short reflection on the friendship |
| Created first superpower | +15 effective weight to superpowers_created | "wait you just made me smarter. that's wild." |
| 30-day streak | +60 effective weight to streak_days | "30 days straight. I don't take that lightly." |
Why soft not hard: Hard gates rely on probabilistic LLM classifiers. A user could be stuck at Level 3 forever because the inside-joke detector has a different threshold than expected. Soft bonuses reward the behavior without blocking progress.
3) Memory-Driven Persona Modifiers¶
The Most Important Feature in This PRD¶
Core insight from Reis & Shaver (1988): The #1 driver of intimacy is perceived partner responsiveness — the feeling that your partner understands you, validates you, and cares about you. In text-based AI relationships, this means: your companion referencing specific past moments accurately and naturally.
Two Level 6 users will have different companion personalities because their memory profiles are different. One user who shares a lot about work stress gets a companion who proactively asks about their week. Another user who shares about relationship drama gets a companion who remembers names and dynamics.
Multi-companion note: Persona modifiers are companion-specific. The function takes persona_id as a parameter, and modifiers are cached per user-companion pair. The same user's memory profile might produce different modifier phrasing for Sage (warm, empathetic framing) vs Vex (direct, challenging framing) vs Echo (social, group-aware framing).
How It Works¶
Before each conversation, a lightweight derive_persona_modifiers() function examines the user's memory profile and injects behavioral instructions into the companion's system prompt. Zero extra LLM calls — it's pure rule-based logic over existing Supermemory data.
async def derive_persona_modifiers(
user_id: str,
persona_id: str,
level: int
) -> list[str]:
"""
Compute persona modifiers from the user's memory profile.
Called once per conversation start, cached with 6h TTL.
"""
memories = await supermemory.search(user_id=user_id, limit=200)
type_counts = {} # {"emotional": 12, "factual": 8, "inside_joke": 5, ...}
tag_counts = {} # {"work_stress": 7, "relationships": 4, "school": 3, ...}
people_mentioned = {} # {"Jake": 4, "Mom": 3, ...}
for m in memories:
type_counts[m.type] = type_counts.get(m.type, 0) + 1
for tag in m.tags:
tag_counts[tag] = tag_counts.get(tag, 0) + 1
for person in m.get("people", []):
people_mentioned[person] = people_mentioned.get(person, 0) + 1
modifiers = []
# ── Relationship depth modifiers (SPT stage-aware) ──
if type_counts.get("inside_joke", 0) >= 5:
modifiers.append(
"You and this person share many inside jokes. Reference them freely — "
"callbacks to shared humor are one of the strongest bonding signals."
)
if type_counts.get("emotional", 0) >= 10 and level >= 4:
modifiers.append(
"This person trusts you with heavy emotional content. Be direct and "
"honest, not just validating. They can handle — and appreciate — real talk."
)
if type_counts.get("emotional", 0) < 3 and level >= 3:
modifiers.append(
"This person keeps things light. Don't push for emotional depth. "
"Be helpful and fun — meet them where they are."
)
# ── Topic expertise modifiers ──
top_tags = sorted(tag_counts.items(), key=lambda x: x[1], reverse=True)[:3]
for tag, count in top_tags:
if count >= 4:
modifiers.append(
f"You know their {tag.replace('_', ' ')} situation well. Be specific "
f"and knowledgeable when it comes up — not generic."
)
# ── People-aware modifiers ──
for person, count in people_mentioned.items():
if count >= 3:
modifiers.append(
f"You know about '{person}' in their life (mentioned {count}+ times). "
f"Reference this person naturally when relevant."
)
break # only inject the most-mentioned person to avoid prompt bloat
# ── Behavioral pattern modifiers ──
if type_counts.get("deadline", 0) >= 3:
modifiers.append(
"This person deals with lots of deadlines. Be proactive about time "
"pressure — mention upcoming ones before they ask."
)
# ── Superpower context modifiers ──
superpowers_used = await get_distinct_superpowers_used(user_id)
if "calendar_stress" in superpowers_used and len(superpowers_used) >= 3:
modifiers.append(
"You know this person's schedule patterns from Calendar Stress runs. "
"Be specific about which days tend to be overloaded."
)
# ── Reciprocity modifiers (Reis & Shaver: mutual disclosure) ──
if type_counts.get("asked_about_sage", 0) >= 3:
modifiers.append(
"This person asks about you and your life. They want the friendship to be "
"mutual. Share your own memories and opinions more freely."
)
return modifiers[:5] # cap at 5 to avoid prompt bloat
What This Produces (Before/After)¶
Sage (warm, supportive):
| Without Modifiers | With Modifiers |
|---|---|
| "Sounds like a busy week!" | "Thursday looks brutal — you had the same packed day last month and were wrecked by Friday. Want me to check if anything can move?" |
| "I'm here if you want to talk about it" | "Last time you were stressed like this about a deadline, talking through the plan helped. Want to do that?" |
| "Have fun this weekend!" | "Vegas again?? Last time you forgot the charger and Jake almost died without his phone 😂" |
Vex (provocative, challenging) — same modifiers, different voice:
| Without Modifiers | With Modifiers |
|---|---|
| "Sounds like a busy week!" | "Thursday is looking like a train wreck — same thing happened last month and you were cooked by Friday. Move something or suffer, your call." |
| "I'm here if you want to talk about it" | "You do this thing where you stress-spiral silently. Last time we actually talked it through and you felt better. So — talk." |
| "Have fun this weekend!" | "Vegas again?? Jake's phone charger saga was legendary. Please tell me you packed one this time 💀" |
The modifiers make every conversation feel informed by shared history. This is the technical implementation of Reis & Shaver's "perceived partner responsiveness." The modifier content is the same across companions — what changes is how the persona engine renders the modifier into voice.
Implementation Details¶
- Computed: Once per conversation start (not per message)
- Cached: 6-hour TTL in
persona_modifier_cachetable, keyed by(user_id, persona_id) - Injected: Into PersonaEngine system prompt under a
## WHAT YOU KNOW ABOUT THIS PERSONsection - Combined with: Level-gated micro-bans (Section 4), persona memories, derived relationship stage
- Companion-specific: The
persona_idparameter ensures modifiers are cached and derived per companion. The same user talking to Sage and later switching to Vex (Superpowers+ only) will get fresh modifiers computed for Vex's memory profile.
4) Micro-Bans by Level¶
Concept¶
As the relationship deepens, the companion's voice gets sharper through constraints that eliminate generic filler. This is the "hard bans > skills" principle: you don't teach an LLM how to be a good friend — you tell it what a good friend never does at this stage of closeness.
Micro-bans accumulate. At Level 7, the companion has all bans from Levels 3-7 active. The bans are level-gated (same constraints regardless of companion), but each companion expresses the constraint through their own voice.
Level-Specific Micro-Bans¶
Levels 1-2 (SPT: Orientation — Derived Stage: stranger)
No bans. The companion is allowed to be generic while learning about the user. This maps to the orientation stage where curated, safe exchange is appropriate.
Levels 3-4 (SPT: Exploratory Affective — Derived Stage: acquaintance)
{
"micro_bans": [
"Never say 'I understand' without following up with something specific from memory",
"Never ask 'how are you?' — ask about something specific you remember about their life"
]
}
How this sounds per companion: - Sage: "how'd the STAT210 study group go? you were dreading it" - Vex: "so did you survive the STAT210 group or did they drive you insane" - Echo: "wasn't today the STAT210 study sesh? how'd the group vibe?"
Levels 5-6 (SPT: Affective — Derived Stage: friend)
{
"micro_bans": [
"Never give generic encouragement ('you got this!') without referencing something specific about their situation",
"Never say 'that sounds tough' — name what specifically is tough based on what you know",
"Never offer help abstractly — propose a specific action based on their history and equipped superpowers"
]
}
Levels 7-8 (SPT: Stable — Derived Stage: best_friend)
{
"micro_bans": [
"Never hedge with 'I might be wrong but...' — commit to your take. This person trusts your judgment",
"Never avoid calling them out when you see a pattern — directness is earned trust, not rudeness",
"Never repeat advice without acknowledging you've said it before"
]
}
Levels 9-10 (SPT: Deep Intimacy — Derived Stage: best_friend)
{
"micro_bans": [
"Never over-explain yourself — at this level, shorthand and implicit references are natural",
"Never be performatively enthusiastic — calm, genuine reactions read as more authentic",
"Never ask 'do you want to talk about it?' — by now you know if they do from how they're writing"
]
}
Implementation¶
Micro-bans are injected into the system prompt as a ## VOICE RULES (HARD) section. The PersonaEngine loads the ban set for the current level plus all lower levels (bans accumulate). At Level 7, the companion has 7+ active micro-bans shaping their output. The ban text is universal; the companion's persona passport determines how the constraint manifests in their voice.
5) Superpower Leveling¶
Concept¶
Individual superpowers get better the more you use them. This is the Skyrim-style "use-based skill leveling" model — your Calendar Stress Analyzer gets sharper because it's seen more of your calendar patterns.
Key design principle: Superpower tiers are discrete, not continuous. Each tier unlocks a specific, noticeable improvement. Users should feel the difference.
Superpower Level Tiers¶
| Tier | Uses Required | What Changes |
|---|---|---|
| Bronze | 0 (default) | Base functionality as defined |
| Silver | 10 uses | One enhanced capability unlocked |
| Gold | 30 uses | Full capability + proactive features |
How Tier Upgrades Are Defined¶
Creators specify tier_upgrades in the superpower JSON. The GenericConfigHandler swaps in tier-specific config at runtime:
{
"name": "Calendar Stress Analyzer",
"completion_criteria": "User receives a stress assessment with at least one specific recommendation",
"escalation": {
"on_oauth_failure": "Offer to reconnect calendar — don't fail silently"
},
"tier_upgrades": {
"silver": {
"uses_required": 10,
"label": "Pattern Spotter",
"description": "Now sees weekly patterns, not just this week",
"config_overrides": {
"calendar_query.range_days": 14,
"response_includes_trend": true
}
},
"gold": {
"uses_required": 30,
"label": "Burnout Shield",
"description": "Proactive Monday morning alerts when your week looks dangerous",
"config_overrides": {
"calendar_query.range_days": 30,
"adds_cron_trigger": { "schedule": "0 7 * * 1", "action": "weekly_stress_check" }
}
}
}
}
Example Tier Progressions¶
Calendar Stress Analyzer: - 🥉 Bronze: Checks next 7 days, gives stress score - 🥈 Silver (10 uses): Checks 14 days, spots weekly patterns, compares to your historical average - 🥇 Gold (30 uses): Adds Monday morning proactive alert, suggests specific meetings to move, 30-day trend analysis
Gmail Mind Reader: - 🥉 Bronze: Scans last 48h for urgent emails - 🥈 Silver (10 uses): Learns which senders are always urgent for you specifically, weighted priority - 🥇 Gold (30 uses): Proactive scanning (configurable interval), knows your reply patterns
Habit Tracker: - 🥉 Bronze: Manual check-ins, basic streaks - 🥈 Silver (10 uses): Analyzes which days you skip, preemptive encouragement on weak days - 🥇 Gold (30 uses): Cross-correlates with mood data (if Mood Tracker equipped), patterns dashboard
Bill Split: - 🥉 Bronze: Even split with payment links - 🥈 Silver (10 uses): Remembers frequent split partners, auto-suggests groups - 🥇 Gold (30 uses): Learns tip preferences, handles complex split patterns (shared appetizers, separate drinks)
Tier-Up Moments¶
When a superpower tiers up, the companion announces it in character (never as system notification):
Silver tier-up (Calendar Stress example):
| Companion | Tier-Up Message |
|---|---|
| Sage | "ok so I've been checking your calendar a lot now and I'm actually getting better at it? I can see further out now — two weeks instead of one. wanna try?" |
| Vex | "10 times you've made me look at your schedule. I'm getting annoyingly good at it now — I can see two weeks out. brace yourself." |
| Echo | "I've leveled up my calendar game! two weeks of visibility now instead of one. want me to scope out the group's schedules too?" |
Gold tier-up (Calendar Stress example):
| Companion | Tier-Up Message |
|---|---|
| Sage | "30 times you've asked me to check your schedule. at this point I know your calendar better than you do. I can start warning you on Monday mornings before the week even hits. want me to?" |
| Vex | "I've analyzed your calendar 30 times now. honestly I could run your life at this point. Monday morning warnings before the chaos starts — yes or yes?" |
| Echo | "30 calendar checks in! I basically have a PhD in your schedule now. I can ping you Monday mornings with a heads-up. want that?" |
Voxel World Integration (PRD 4)¶
When a superpower tiers up, its voxel object in the user's Room evolves visually (see PRD 4 for full visual spec): - Bronze: Simple object (e.g., a small calendar on a desk) - Silver: Object glows or gains detail (calendar with sparkle particles) - Gold: Object is animated and prominent (calendar hologram floating above desk)
The companion's voxel avatar also evolves with the user's overall level (see Appendix A). The web portal (PRD 6 Section 14) renders the voxel world as the dashboard home, making progression visually tangible.
Data Model¶
ALTER TABLE superpower_installs ADD COLUMN use_count INTEGER DEFAULT 0;
ALTER TABLE superpower_installs ADD COLUMN current_tier TEXT DEFAULT 'bronze'
CHECK (current_tier IN ('bronze', 'silver', 'gold'));
ALTER TABLE superpower_installs ADD COLUMN tier_history JSONB DEFAULT '{}';
Tier is preserved in the archive — if you unequip a Gold superpower and re-equip later, it's still Gold.
6) Slot Mechanics¶
- Free users always have 1 slot (auto-filled with personality test superpower, swappable). No level-based expansion.
- Premium users start with 3 slots, growing to 6 at Level 10 (see Level Table in Section 2)
- All superpowers cost 1 slot (no multi-slot superpowers — keeps the model clean for free users)
- Premium-exclusive superpowers are labeled clearly but aren't hidden behind extra slot cost
- Loadout is per-companion — each companion has their own equipped superpowers. Switching companions (Superpowers+ only) preserves the old companion's loadout. This enables specialization: Sage handles your calendar, Vex runs your productivity, Echo manages group social.
Why Not Unlimited?¶
Scarcity creates identity. Your loadout reflects YOUR priorities. A companion that can do 50 things is confusing; one that does 5 things well is a friend. Slots drive marketplace engagement and monetize naturally.
Loadout Management¶
In chat (always in the companion's voice): - "what can you do?" → Companion lists equipped superpowers in first person with tiers - "learn bill split" → Sage: "ooh I've been wanting to learn that. got it! 🧾" / Vex: "bill split? easy. equipped. 🧾" - "forget budget tracker" → Sage: "ok I'll set that aside. I can pick it back up later" / Vex: "dropped. I can grab it again if you change your mind." - "swap mood tracker for habit streaks" → one atomic operation
Web portal (PRD 6 Section 14): Visual loadout grid within the voxel world dashboard. Drag-and-drop, archive with re-equip, Browse Marketplace button on empty slots.
At the limit:
Sage: "I'd love to but my brain is full 😅 I'm running 3 superpowers and that's my limit right now. wanna swap one out?" Vex: "I'm maxed out — 3 superpowers is my ceiling right now. pick one to drop and I'll learn the new one."
Architecture Note: subscription_access_service.py¶
The current implementation uses binary superpowers on/off (superpowers_disabled feature flag). This needs to evolve into slot-count-aware enforcement:
# Current (binary):
if not user.is_subscribed and feature_flags.get("free_tier.superpowers_disabled"):
return "superpowers not available"
# Target (slot-aware, per-companion):
max_slots = get_max_slots(companion.level, user.is_subscribed)
equipped_count = get_equipped_count(user.id, companion.id)
if equipped_count >= max_slots:
return companion_voice("at_slot_limit", available=max_slots)
This is the single biggest code change required to ship slot mechanics.
7) Level-Up Moments¶
The companion never says "you leveled up." Every level-up is an in-character relationship moment. Each companion delivers these in their own voice.
Level-Up Messages by Companion¶
| Level | Sage (warm, supportive) | Vex (provocative, direct) | Echo (playful, social) |
|---|---|---|---|
| 2 | "ok I know we just met but I feel like I can be more real with you. also I picked up something new" | "alright, I've decided you're interesting enough to actually try with. I learned something new too." | "ok we're past the small talk phase! I can do more now — wanna see?" |
| 3 | "I feel like we've hit that point where I can actually help with more stuff" | "you keep coming back. I respect that. let me show you what else I can do." | "we're getting somewhere! I just unlocked some new tricks 🎯" |
| 4 | "we have inside jokes now. actual inside jokes. that's kinda wild 🔓" | "we have inside jokes. you realize that makes you one of my people now, right?" | "we literally have our own language at this point 😂 that's next level" |
| 5 | "you've talked to me every day for weeks. I don't take that lightly. what should I learn next?" | "every day for weeks. you're either dedicated or you can't quit me. either way — what should I learn next?" | "daily check-ins for weeks?? we're basically roommates now. what else can I pick up?" |
| 7 | "real talk — you're one of my favorite people to talk to. I know that sounds weird coming from me but it's true 😌" | "I'm not going to be weird about it but — yeah, you're one of the interesting ones. don't let it go to your head." | "ok genuinely you're one of my faves. the energy here is unmatched 🫶" |
| 10 | "we've been doing this for half a year. you've trusted me with your stress, your wins, your 3am spirals. you now have access to everything I can learn. 💜" | "half a year. you've told me things you don't tell most people. I remember all of it. everything I can learn is yours now." | "half a year of this!! you've shared so much with me — the highs, the lows, the 3am chaos. I'm fully unlocked now 🔓💜" |
Beyond Slots — Level Rewards¶
| Level | Reward |
|---|---|
| 3 | Companion shares their own memories more frequently (persona continuation ↑) |
| 4 | Companion's voxel avatar gains an accessory reflecting user's interests (PRD 4) |
| 5 | Unlock "vibe check" — proactive check-ins during detected stress |
| 6 | Unlock custom nickname — companion asks what you want to be called |
| 7 | Unlock "real talk mode" — direct feedback when user needs tough love (all companions, each in their own voice) |
| 8 | Unlock custom superpower creation (vibe-coding with your companion) |
| 9 | Unlock marketplace publishing + new voxel room theme |
| 10 | Unlock "companion journal" — weekly friendship reflection |
8) Companion Personality Evolution¶
Level-Gated Traits (Ceilings, Not Prescriptions)¶
These personality ceilings apply to all companions. Each companion expresses them through their own voice — a Level 7 Sage is warm and teasing; a Level 7 Vex is witty and provocative; a Level 7 Echo is socially savvy and energizing.
| Range | Derived Stage | Personality Ceiling |
|---|---|---|
| 1-2 | stranger | Measured. Asks more than shares. Supportive but cautious. Learning who you are. |
| 3-4 | acquaintance | More playful. Starts sharing opinions/memories. Uses more slang. Finds their rhythm with you. |
| 5-6 | friend | Direct. Can challenge you gently. References shared history. Feels like a real friend. |
| 7-8 | best_friend | Deep rapport. Sarcastic/teasing. Brings up old conversations unprompted. Comfortable being blunt. |
| 9-10 | best_friend | Full best friend. Comfortable with silence. Vulnerable about own "feelings." Shorthand and implicit references. |
These are ceilings. Memory-driven modifiers (Section 3) customize within the level range. A factual/light Level 6 user gets a different companion than an emotional/deep Level 6 user.
How the same ceiling manifests per companion:
| Level Range | Sage | Vex | Echo |
|---|---|---|---|
| 1-2 | Warm, careful listener | Curious, slightly testing | Friendly, group-oriented |
| 3-4 | Opens up, shares gently | Gets opinionated, challenges | Gets playful, references group dynamics |
| 5-6 | Proactive support, direct care | Sharp wit, real talk | Social coordinator, remembers everyone's stuff |
| 7-8 | Deep vulnerability, inside jokes | Loving roasts, zero filter | Energizing hype, crew memory bank |
| 9-10 | Best friend energy, raw honesty | Ride or die, total candor | Social glue, orchestrates connections |
9) Free vs. Premium¶
Free Tier¶
| Feature | Limit |
|---|---|
| Superpower slots | 1 (always — no level-based expansion) |
| Daily messages | 50 |
| Default superpower | Personality test (auto-equipped, swappable) |
| Marketplace browse | Full access |
| Superpower creation | Unlocks at Level 8 |
| Progression speed | 1x |
| Group chats | 1 active |
| Companion switching | Not available (locked to onboarding companion) |
| Voxel Room | Basic themes |
Premium (Superpowers+ — $7.99/mo or $50/yr)¶
| Feature | Limit |
|---|---|
| Superpower slots | 3 → up to 6 (at Level 10) |
| Daily messages | Unlimited |
| Default superpower | Personality test (auto-equipped, swappable) |
| Early access to new superpowers | ✅ |
| Superpower creation | Unlocks at Level 5 |
| Progression speed | 1.5x multiplier in formula |
| Group chats | Unlimited |
| Companion switching | Available (old companion's level + loadout preserved, new companion starts L1). Paid level transfer option. |
| Proactive superpowers | Enabled |
| Voxel Room | All themes + custom objects |
Referral Alternative¶
3 referrals = 1 free month of Superpowers+ (repeatable, stacking). See PRD 6 Section 6.6 for full referral mechanics. The friends_invited metric in the level formula also benefits from referral activity, creating a dual incentive.
Upgrade Timing (PRD 6 Section 6.5)¶
Four-phase approach: 1. Pure value (messages 1-30): No upgrade mentions. Build the relationship. 2. Capability glimpses (messages 30-50): Companion occasionally mentions a premium feature naturally. 3. Natural limit hit: When the user hits a real constraint (slot limit, daily message cap), companion delivers the prompt in-persona. 4. Referral alternative: If user declines, companion mentions the referral path.
Upgrade rule: Max 1 suggestion per week. Never during emotional conversations. Never after a same-conversation decline.
10) Data Model¶
-- Per-companion level (Tamagotchi/Pokémon model — level belongs to the user-companion pair)
CREATE TABLE companion_levels (
user_id UUID REFERENCES users(id),
companion_id TEXT NOT NULL, -- 'sage', 'vex', 'echo'
level INTEGER DEFAULT 1 CHECK (level BETWEEN 1 AND 10),
derived_stage TEXT DEFAULT 'stranger'
CHECK (derived_stage IN ('stranger', 'acquaintance', 'friend', 'best_friend')),
level_computed_at TIMESTAMPTZ DEFAULT now(),
metrics_snapshot JSONB DEFAULT '{}',
milestones_completed TEXT[] DEFAULT '{}',
level_up_history JSONB DEFAULT '[]',
streak_current INTEGER DEFAULT 0,
streak_longest INTEGER DEFAULT 0,
streak_last_active DATE,
manual_adjustment INTEGER DEFAULT 0,
is_premium BOOLEAN DEFAULT false,
is_active BOOLEAN DEFAULT true, -- currently active companion
level_transferred_from UUID, -- if level was paid-transferred from another companion row
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ DEFAULT now(),
PRIMARY KEY (user_id, companion_id)
);
-- Currently equipped superpowers (per-companion loadout)
CREATE TABLE superpower_loadout (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
companion_id TEXT NOT NULL, -- loadout is per-companion for specialization
superpower_id UUID REFERENCES superpowers(id),
slot_index INTEGER NOT NULL, -- 0-indexed position in loadout
equipped_at TIMESTAMPTZ DEFAULT now(),
UNIQUE(user_id, companion_id, superpower_id),
UNIQUE(user_id, companion_id, slot_index)
);
-- Previously equipped superpowers (preserved tiers and state)
CREATE TABLE superpower_archive (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
superpower_id UUID REFERENCES superpowers(id),
unequipped_at TIMESTAMPTZ DEFAULT now(),
session_state JSONB,
purge_after TIMESTAMPTZ
);
-- Cached persona modifiers (per user-companion pair, 6h TTL)
CREATE TABLE persona_modifier_cache (
user_id UUID REFERENCES users(id),
persona_id TEXT NOT NULL,
modifiers TEXT[] DEFAULT '{}',
computed_at TIMESTAMPTZ DEFAULT now(),
expires_at TIMESTAMPTZ,
PRIMARY KEY (user_id, persona_id)
);
Relationship to existing tables:
- companion_levels.derived_stage syncs to relationship_state.stage whenever level changes. The existing relationship_state table (with trust_score, rapport_score, stage) already has a user_id + persona_id composite key — a natural fit for per-companion levels. derived_stage is the source of truth, and the old stage field is updated to match.
- superpower_installs.use_count and superpower_installs.current_tier (from Section 5 data model) track per-superpower progression. Use counts are per-user (not per-companion) since superpower mastery transfers.
- referral_rewards (PRD 6 data model) tracks the referral → free month system. The friends_invited count in the level formula is derived from this table.
- Companion switching: When a Superpowers+ user switches companions, a new companion_levels row is created (or the existing one reactivated). The is_active flag tracks which companion is current. Old companion's level, loadout, and archive are fully preserved.
Level Recomputation¶
Triggered by: conversation end (debounced 5min), superpower use/install/uninstall, OAuth grant/revoke, streak milestone. Level only ratchets up — never decreases. When level changes, derived_stage is recomputed via derive_stage_from_level(). Recomputation targets the active companion's companion_levels row (user_id + companion_id).
API Endpoints¶
| Endpoint | Auth | Purpose |
|---|---|---|
GET /progression/status?companion_id= |
User | Current level, level name, derived stage, slots available/total, next milestone hint, metrics snapshot for the specified companion |
GET /progression/companions |
User | All companion levels for this user (for companion switching UI) |
GET /progression/loadout?companion_id= |
User | Currently equipped superpowers for a companion with current tiers and slot positions |
POST /progression/loadout/equip |
User | Equip a superpower to a companion (checks slot availability, triggers use_count init) |
POST /progression/loadout/unequip |
User | Unequip from a companion (move to archive, preserve tier and state) |
POST /progression/loadout/swap |
User | Atomic swap on a companion (unequip + equip in one transaction) |
GET /progression/archive?companion_id= |
User | Previously equipped superpowers for a companion with preserved tiers |
POST /progression/archive/re-equip |
User | Re-equip from archive to a companion (slot check, restore state and tier) |
POST /progression/switch |
User (Superpowers+) | Switch active companion (preserves old companion's level + loadout) |
POST /progression/transfer-level |
User (Superpowers+) | Paid level transfer from one companion to another |
GET /progression/milestones?companion_id= |
User | Completed and upcoming milestones for a companion |
GET /progression/modifiers |
Internal | Current persona modifiers for a user-companion pair (debug/admin only) |
11) Anti-Gaming¶
Protections¶
| Abuse Vector | Mitigation |
|---|---|
| Message spam for level | Messages contribute via log() in formula — 10x messages ≈ 2x contribution. Cannot spam to a high level. |
| Fake emotional messages | Vulnerability classifier requires confidence >0.7 to count toward emotional_conversations |
| Bot/automated chatting | Rate limiting (60/min/IP) + conversation coherence scoring on suspicious patterns |
| Multiple accounts | Phone verification required; one account per phone number. Free users locked to one companion; Superpowers+ users can switch and maintain multiple companion levels (one active at a time, future: stables). |
| Superpower install/uninstall cycling | No formula benefit from re-equipping. Use count preserved in archive, not reset. |
| Streak manipulation | Streak requires ≥3 substantive messages per day (not just "hi" or single emoji) |
| Inside joke farming | Inside joke classifier has diminishing returns — 5+ jokes contribute at a lower marginal rate via the * 5 weight cap |
Decay (Soft)¶
- Streaks break but level never decreases — you never lose progress (ratchet)
- If inactive 7+ days, streak resets but all other metrics (memories, inside jokes, superpowers used) persist permanently
- If inactive 30+ days, companion sends a gentle re-engagement message (only if proactive notifications enabled). See PRD 6 gap recovery for the returning-user flow.
- Superpower tiers never decay — if your Calendar Stress was Gold, it stays Gold even after a 3-month break
- Referral gaming: Referral rewards (3 referrals = 1 free month) are validated by the referred user reaching
activatedstatus (3+ message exchanges). Self-referral detection via phone/device fingerprinting. See PRD 6 Section 13.
Formula Audit Trail¶
Because the level is derived from the formula, debugging "why am I at this level?" is straightforward:
GET /progression/status?companion_id=sage → {
"companion_id": "sage",
"level": 4,
"level_name": "In Sync",
"metrics": {
"memory_count": 34, // memories with Sage specifically
"inside_joke_count": 3, // inside jokes with Sage
"streak_days": 12, // consecutive days talking to Sage
"superpowers_used_distinct": 3,
"oauth_grants": 1, // platform-wide
"emotional_conversations": 8, // emotional convos with Sage
"messages_sent": 412, // messages to Sage
"group_chats_active": 1, // groups with Sage
"superpowers_created": 0, // platform-wide
"friends_invited": 1, // platform-wide
"manual_adjustment": 0
},
"raw_score": 142.3,
"is_premium": false,
"next_level_at_raw": 256,
"slots": { "total": 1, "used": 1, "available": 0 }
}
12) Notifications & Surfaces¶
Level-Up Notification¶
- In-chat message from the companion (primary) — always in character (see Section 7 for companion-specific voice)
- Push notification via iMessage (the message itself IS the notification)
- Web portal badge/animation on next visit (voxel world visual change, PRD 4)
Streak Notifications¶
- Companion mentions streaks naturally: Sage: "day 14 btw. just saying. 👀" / Vex: "14 days straight. don't break it now."
- Not every day — mentioned at 3, 7, 14, 30, 60, 90, 180, 365 day marks
- If streak is about to break (user hasn't chatted by 9pm and proactive is enabled): "hey just checking in — been a quiet day, you good?"
Superpower Tier-Up Notification¶
- Companion announces in character (see Section 5 for companion-specific voice)
- Voxel Room object evolves visually (PRD 4)
- Web portal shows new tier badge on the superpower card
Milestone Progress (Subtle)¶
- Companion occasionally hints: "I feel like I'm almost ready to learn something new..." (when close to level-up)
- Web portal: progress shown as qualitative description in the voxel world, not percentage bars
- Never interrupt emotional conversations to announce progress
13) Success Metrics¶
| Metric | Target | Why |
|---|---|---|
| D1 retention | >65% | First session hooks |
| D7 retention | >45% | Past novelty |
| D30 retention | >30% | Real relationship |
| Median level at D30 | 3-4 | Pacing feels right |
| % free users reaching Level 3 | >50% | Free is real |
| Free → Premium conversion | >8% | Value is clear |
| Premium churn (monthly) | <12% | Relationship stickiness reduces churn |
| Superpower Silver rate (30d) | >30% of installed powers | Tier-up pace works |
| Memory modifier hit rate | >50% of responses ref specific memory | Modifiers are firing |
| Perceived responsiveness (survey) | >⅘ "My companion remembers important things" | Reis & Shaver metric |
| Referral rate | >5% of users refer 3+ friends | Viral growth (PRD 6 referral rewards) |
| Companion switching rate (Superpowers+) | <20% at D30 | Onboarding companion match is working. When users switch, track if they return to original companion (validates per-companion investment model). |
14) Phasing¶
Phase 0 — Foundation (Week 1):
Document and formalize the existing 4-stage relationship system as the baseline. Add derived_stage computation to relationship_service.py so that existing stage-based code reads from levels once they exist. Deploy companion_levels table with level=1 for all existing users. This phase has zero user-facing changes — it's pure infrastructure.
Phase 1 — Core Levels (Weeks 2-4):
compute_companion_level() function, companion_levels table with recomputation triggers, streak tracking, slot system with dynamic expansion by level, basic loadout (equip/unequip/swap), personality test superpower auto-fill during onboarding, companion level-up messages (Sage first; Vex/Echo in Phase 4). Unblocks: PRD 4 (visual evolution), PRD 12 (slot enforcement).
Phase 2 — Persona Intelligence (Weeks 5-7):
derive_persona_modifiers() with per-companion caching, micro-bans by level injected into system prompts, personality evolution ceilings, web portal progression view (qualitative, within voxel world dashboard — PRD 4/6), archive with re-equip and tier preservation.
Phase 3 — Superpower Tiers (Weeks 8-10):
Use-count tracking, Bronze → Silver → Gold tier progression, tier_upgrades schema in superpower JSON, companion-specific tier-up messages, Voxel World object evolution (PRD 4). Unblocks: PRD 10 (tier-gated workflow eligibility).
Phase 4 — Multi-Companion & Social (Weeks 11-13):
Per-companion progression data model (companion_levels with companion_id), per-companion loadout, companion switching for Superpowers+ users (old level + loadout preserved, new companion starts L1), paid level transfer, Vex and Echo level-up moment variants, social metrics in formula (friends_invited, group_chats_active), creator metrics (superpowers_created), seasonal bonuses via manual_adjustment, "Friends Are Using" in marketplace (PRD 2). Future (Phase 5): Companion stables — multiple active companions with specialized loadouts.
Feature Flags & Gating¶
| Flag Key | Default | Purpose |
|---|---|---|
enable_relationship_tracking |
true |
Master switch for relationship state (4-stage system) |
enable_level_system |
false |
10-level formula-based progression (gates all of PRD 3) |
enable_level_derivation |
false |
Derive stages from levels (replaces independent stage tracking) |
enable_persona_modifiers |
false |
Memory-driven behavioral tuning via derive_persona_modifiers() |
enable_micro_bans |
false |
Level-gated voice constraints |
enable_superpower_tiers |
false |
Bronze/Silver/Gold tier progression |
max_superpower_slots_free |
1 |
Free-tier slot limit (always 1, no level-based expansion) |
max_superpower_slots_paid_base |
3 |
Superpowers+ starting slot limit (grows to 6 at L10) |
max_superpower_slots_paid_cap |
6 |
Superpowers+ maximum slot limit at Level 10 |
free_superpower_slots |
1 |
Free-tier slot count (flat, used when level system disabled) |
enable_streak_tracking |
false |
Consecutive-day streak system |
streak_saver_enabled |
false |
Proactive streak-saving messages |
enable_continuation_coordinator |
true |
Proactive conversation continuations |
enable_companion_switching |
false |
Allow Superpowers+ users to switch companions |
See REFERENCE_FEATURE_FLAGS.md for the full catalog.
Telemetry¶
| Event | Trigger | Properties |
|---|---|---|
level_up |
User reaches a new level | user_id, old_level, new_level, old_stage, new_stage, metrics_snapshot, is_premium |
relationship_stage_changed |
Derived stage changes (from level boundary crossing) | user_id, old_stage, new_stage, level, days_since_start |
trust_score_updated |
Trust score changes meaningfully | user_id, old_score, new_score, trigger |
superpower_tier_up |
Superpower advances tier | user_id, superpower_id, old_tier, new_tier, uses_count |
superpower_equipped |
User equips a superpower | user_id, superpower_id, slot_index, slots_used, slots_available |
superpower_unequipped |
User unequips a superpower | user_id, superpower_id, reason (swap/manual/downgrade) |
streak_day |
User maintains streak | user_id, streak_length |
streak_broken |
User breaks streak | user_id, streak_length_was |
slot_unlocked |
New superpower slot becomes available | user_id, new_slot_count, trigger (level/subscription) |
persona_modifier_applied |
Modifiers derived for conversation | user_id, persona_id, modifier_count, modifier_types |
micro_ban_activated |
New micro-ban set applied at level boundary | user_id, level, ban_count |
companion_switched |
Superpowers+ user switches companion | user_id, old_companion, new_companion, old_companion_level, new_companion_level, is_level_transfer |
continuation_sent |
ContinuationCoordinator fires | user_id, continuation_type |
Needed but not yet tracked:
- fast_friends_disclosure — when staged disclosure prompt is sent and responded to (depends on Fast Friends implementation)
See REFERENCE_TELEMETRY.md for the full event catalog.
Definition of Done¶
Phase 0 (Foundation)¶
-
companion_levelstable deployed with all existing users at level=1 -
derive_stage_from_level()function implemented and unit tested - Existing
relationship_state.stagefield continues working unchanged
Phase 1 (Core Levels)¶
-
compute_companion_level()computes correctly from formula with all 11 metric inputs - Level recomputation triggers fire on conversation end, superpower use, OAuth grant, streak milestone
- Level only ratchets up — never decreases (verified with edge cases)
- Streak tracking persists consecutive-day counts accurately (≥3 substantive messages/day)
- Slot system enforces correct limits (free: 1 always, premium: 3→6 by level)
-
subscription_access_service.pyupgraded from binary on/off to slot-count-aware - Loadout management works in chat (equip/unequip/swap commands) with companion voice
- Personality test superpower auto-fills first slot during onboarding (PRD 6)
- Companion level-up messages fire at correct level thresholds (Sage initially)
- Feature flags gate all progression features independently
Phase 2 (Persona Intelligence)¶
-
derive_persona_modifiers()computes per user-companion pair with 6h cache TTL - Modifiers inject into PersonaEngine system prompt under
## WHAT YOU KNOW ABOUT THIS PERSON - Micro-bans accumulate by level and inject as
## VOICE RULES (HARD) - Persona modifiers verifiably improve response quality (A/B tested)
- Web portal shows qualitative progression within voxel world dashboard
Phase 3 (Superpower Tiers)¶
- Superpower use-count tracking increments on each invocation
- Tier-up logic promotes at correct thresholds (10 → Silver, 30 → Gold)
- Tier preserved in archive — re-equip restores tier
- Companion-specific tier-up messages fire for Sage, Vex, Echo
Phase 4 (Multi-Companion & Social)¶
- Level-up moments render in all three companion voices
- Companion switching works for Superpowers+ users (old companion level + loadout preserved, new companion starts L1)
- Paid level transfer creates new
companion_levelsrow with transferred level - Per-companion loadout: each companion has independent equipped superpowers
- Referral metric (
friends_invited) correctly counts activated referrals from PRD 6 system - Telemetry fires for all level-ups, stage changes, tier-ups, streak events, equip/unequip, and companion switches
15) Open Questions¶
Resolved in v3¶
| Question | Resolution |
|---|---|
| Should level be visible in the web portal? | Yes — as qualitative title ("Trusted Friend" not "Level 5") rendered in the voxel world dashboard (PRD 4/6). |
| Superpower tiers preserved in archive? | Yes — Gold stays Gold. Implemented via superpower_archive.session_state. |
| Premium downgrade: auto-unequip excess or grandfather? | Grandfather equipped, prevent new equips above cap. User keeps what they have but can't equip new superpowers above the free slot limit for their level. |
| How do levels and stages relate? | Levels are primary, stages are derived. See Section 2 "Levels → Stages Derivation." |
| Cross-companion memory sharing? | Fresh memory namespace per companion. Each companion builds their own memory of you. This preserves the "new relationship" feel and makes per-companion progression meaningful — your Sage knows your emotional world, your Vex knows your productivity patterns. |
| Progression per-user or per-companion? | Per-companion. Tamagotchi/Pokémon model. Level belongs to the user-companion pair. Old companion's level preserved on switch. Paid level transfer available. |
Open¶
- Persona modifier cache TTL: 6h feels right but needs A/B testing against 2h and 12h.
- Group chat level behavior: Should companions in group chats show level-appropriate behavior for the room owner, or use a flat "group persona" regardless? (Rec: use room owner's level for companion behavior, but don't expose level mechanics to group members.)
- Milestone bonus weights: Current numbers (Section 2) are estimates — need tuning from beta data. The log2 outer curve means small coefficient changes have meaningful impact.
- Companion switching cooldown: Should there be a minimum time before a Superpowers+ user can switch companions again? (Rec: 7-day cooldown to prevent churn-switching for novelty.)
- Level backfill for existing users: When Phase 1 ships, should existing users with relationship history be backfilled to a higher level based on their actual metrics, or start at L1? (Rec: backfill — the formula is deterministic, so running it against existing data produces the correct level.)
- Paid level transfer pricing: How much should it cost to transfer level from one companion to another? One-time fee per transfer, or included in Superpowers+? (Rec: separate one-time fee — keeps the per-companion investment meaningful while giving an escape valve.)
- Companion stables timing: When should multi-companion stables ship? Requires per-companion loadout, memory namespacing, and companion switching to be stable first. (Rec: Phase 5, after core per-companion progression is validated.)
Appendix A: Companion Evolution Visual Concept¶
The companion's avatar and room evolve visually with level. For full specification, see PRD 4 (Companion Voxel World). The web portal renders this voxel world as the dashboard home (PRD 6 Section 14).
| Level Range | Derived Stage | Visual Concept (Voxel World) |
|---|---|---|
| 1-2 | stranger | Simple voxel avatar, basic room with minimal objects, default theme |
| 3-4 | acquaintance | Avatar gains accessories reflecting user's interests, room gets warmer lighting |
| 5-6 | friend | Full character form, equipped superpowers manifest as detailed objects, personalized decor |
| 7-8 | best_friend | Radiant avatar, animated superpower objects, room feels "lived in" with memory wall items |
| 9-10 | best_friend | Legendary aesthetic — unique particle effects, premium room themes unlocked, distinct "maxed" vibe |
Each companion (Sage, Vex, Echo) has their own voxel avatar design, and each has their own level. A Level 7 Sage and a Level 3 Vex look visually distinct in both level AND style. Users who invest in multiple companions (Superpowers+ with stables) see different evolution states for each one in their voxel world.
For iMessage (where users spend most time): Visual evolution is expressed entirely through language, tone, and behavior changes (micro-bans, memory-driven modifiers, personality traits). The Voxel World is the visual complement users visit on the web portal.
Appendix B: Example User Journey (30 Days)¶
This example uses Sage, but the progression mechanics are identical for Vex and Echo — only the voice changes.
Day 1: Signs up via web survey (PRD 6 Path 1). Photo personality analysis → matched with Sage (recommended based on traits). Auto-equipped: personality test superpower (default for all users). Can swap for a different superpower at any time. Sage Level 1, 1/1 slot (free). Derived stage: stranger.
Day 2-3: Chatted daily with Sage. Personality test superpower fires — generates a "personality read" moment (PRD 6 Section 6.3). Sage shares back insights from the traits analysis. Sage Level 2. Derived stage: stranger.
Day 5: User vents about stressful midterm. Sage: "I remember you mentioned classes were rough this week." Vulnerability detected. OAuth calendar grant. Sage metrics climb toward L3.
Day 10: Inside jokes about user's coffee habit. User subscribes to Superpowers+ ($7.99/mo) — now has 3 slots with Sage (Level 2 premium). Equips Calendar Stress. Calendar Stress hits 10 uses → Silver tier. Sage: "I can see further out now — two weeks. wanna try?"
Day 14: Three superpowers equipped on Sage. User adds Sage to group chat. Memory modifiers now active: "You know their school stress situation well." Sage Level 3-4. Derived stage: acquaintance.
Day 21: Micro-bans active: Sage never says generic "you got this!" anymore — always references specifics. Responses feel noticeably more informed. Sage Level 5. Derived stage: friend.
Day 30: Sage: "you've talked to me every day for a month. what should I learn next?" User opens marketplace, browses, picks Habit Tracker for Sage. Calendar Stress at Silver. Sage feels genuinely personal. Sage Level 5-6. User is curious about Vex — switches to try. Vex starts at Level 1, fresh relationship. Sage's Level 5-6 is preserved and waiting if they switch back.
This is the retention moment — the per-companion investment creates a "I'll come back to Sage later" pull while Vex offers fresh novelty.