@gonzih/meet-the-one-ai 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/.env.example +12 -35
  2. package/SPEC.md +202 -0
  3. package/USER_SPEC.md +201 -0
  4. package/package.json +10 -3
  5. package/src/agent.ts +34 -14
  6. package/src/bot.ts +123 -13
  7. package/src/jobs/introduce.ts +176 -0
  8. package/src/jobs/matcher.ts +134 -0
  9. package/src/lib/bluebubbles.ts +91 -0
  10. package/src/lib/intake.ts +66 -0
  11. package/src/lib/logger.ts +14 -0
  12. package/src/mcp-server-matcher.ts +228 -0
  13. package/src/mcp-server.ts +137 -111
  14. package/tsconfig.json +6 -1
  15. package/dist/agent.d.ts +0 -2
  16. package/dist/agent.d.ts.map +0 -1
  17. package/dist/agent.js +0 -114
  18. package/dist/agent.js.map +0 -1
  19. package/dist/api/routes/auth.d.ts +0 -2
  20. package/dist/api/routes/auth.d.ts.map +0 -1
  21. package/dist/api/routes/auth.js +0 -79
  22. package/dist/api/routes/auth.js.map +0 -1
  23. package/dist/api/routes/identity.d.ts +0 -2
  24. package/dist/api/routes/identity.d.ts.map +0 -1
  25. package/dist/api/routes/identity.js +0 -92
  26. package/dist/api/routes/identity.js.map +0 -1
  27. package/dist/api/routes/text-submission.d.ts +0 -2
  28. package/dist/api/routes/text-submission.d.ts.map +0 -1
  29. package/dist/api/routes/text-submission.js +0 -56
  30. package/dist/api/routes/text-submission.js.map +0 -1
  31. package/dist/api/webhooks/twilio.d.ts +0 -2
  32. package/dist/api/webhooks/twilio.d.ts.map +0 -1
  33. package/dist/api/webhooks/twilio.js +0 -144
  34. package/dist/api/webhooks/twilio.js.map +0 -1
  35. package/dist/api/webhooks/vapi.d.ts +0 -2
  36. package/dist/api/webhooks/vapi.d.ts.map +0 -1
  37. package/dist/api/webhooks/vapi.js +0 -177
  38. package/dist/api/webhooks/vapi.js.map +0 -1
  39. package/dist/bot.d.ts +0 -3
  40. package/dist/bot.d.ts.map +0 -1
  41. package/dist/bot.js +0 -39
  42. package/dist/bot.js.map +0 -1
  43. package/dist/index.d.ts +0 -2
  44. package/dist/index.d.ts.map +0 -1
  45. package/dist/index.js +0 -9
  46. package/dist/index.js.map +0 -1
  47. package/dist/jobs/compact-identity.d.ts +0 -2
  48. package/dist/jobs/compact-identity.d.ts.map +0 -1
  49. package/dist/jobs/compact-identity.js +0 -159
  50. package/dist/jobs/compact-identity.js.map +0 -1
  51. package/dist/jobs/consent-call.d.ts +0 -2
  52. package/dist/jobs/consent-call.d.ts.map +0 -1
  53. package/dist/jobs/consent-call.js +0 -70
  54. package/dist/jobs/consent-call.js.map +0 -1
  55. package/dist/jobs/export-identity.d.ts +0 -2
  56. package/dist/jobs/export-identity.d.ts.map +0 -1
  57. package/dist/jobs/export-identity.js +0 -129
  58. package/dist/jobs/export-identity.js.map +0 -1
  59. package/dist/jobs/introduction-call.d.ts +0 -2
  60. package/dist/jobs/introduction-call.d.ts.map +0 -1
  61. package/dist/jobs/introduction-call.js +0 -86
  62. package/dist/jobs/introduction-call.js.map +0 -1
  63. package/dist/jobs/reanalyze-identity.d.ts +0 -2
  64. package/dist/jobs/reanalyze-identity.d.ts.map +0 -1
  65. package/dist/jobs/reanalyze-identity.js +0 -56
  66. package/dist/jobs/reanalyze-identity.js.map +0 -1
  67. package/dist/jobs/run-matching.d.ts +0 -2
  68. package/dist/jobs/run-matching.d.ts.map +0 -1
  69. package/dist/jobs/run-matching.js +0 -200
  70. package/dist/jobs/run-matching.js.map +0 -1
  71. package/dist/jobs/scheduled-matching.d.ts +0 -2
  72. package/dist/jobs/scheduled-matching.d.ts.map +0 -1
  73. package/dist/jobs/scheduled-matching.js +0 -44
  74. package/dist/jobs/scheduled-matching.js.map +0 -1
  75. package/dist/jobs/transcribe-session.d.ts +0 -2
  76. package/dist/jobs/transcribe-session.d.ts.map +0 -1
  77. package/dist/jobs/transcribe-session.js +0 -66
  78. package/dist/jobs/transcribe-session.js.map +0 -1
  79. package/dist/lib/anthropic.d.ts +0 -4
  80. package/dist/lib/anthropic.d.ts.map +0 -1
  81. package/dist/lib/anthropic.js +0 -32
  82. package/dist/lib/anthropic.js.map +0 -1
  83. package/dist/lib/config.d.ts +0 -57
  84. package/dist/lib/config.d.ts.map +0 -1
  85. package/dist/lib/config.js +0 -73
  86. package/dist/lib/config.js.map +0 -1
  87. package/dist/lib/deepgram.d.ts +0 -15
  88. package/dist/lib/deepgram.d.ts.map +0 -1
  89. package/dist/lib/deepgram.js +0 -37
  90. package/dist/lib/deepgram.js.map +0 -1
  91. package/dist/lib/inngest.d.ts +0 -42
  92. package/dist/lib/inngest.d.ts.map +0 -1
  93. package/dist/lib/inngest.js +0 -7
  94. package/dist/lib/inngest.js.map +0 -1
  95. package/dist/lib/openai.d.ts +0 -3
  96. package/dist/lib/openai.d.ts.map +0 -1
  97. package/dist/lib/openai.js +0 -13
  98. package/dist/lib/openai.js.map +0 -1
  99. package/dist/lib/prompts.d.ts +0 -8
  100. package/dist/lib/prompts.d.ts.map +0 -1
  101. package/dist/lib/prompts.js +0 -258
  102. package/dist/lib/prompts.js.map +0 -1
  103. package/dist/lib/r2.d.ts +0 -7
  104. package/dist/lib/r2.d.ts.map +0 -1
  105. package/dist/lib/r2.js +0 -49
  106. package/dist/lib/r2.js.map +0 -1
  107. package/dist/lib/session-helpers.d.ts +0 -8
  108. package/dist/lib/session-helpers.d.ts.map +0 -1
  109. package/dist/lib/session-helpers.js +0 -31
  110. package/dist/lib/session-helpers.js.map +0 -1
  111. package/dist/lib/supabase.d.ts +0 -2
  112. package/dist/lib/supabase.d.ts.map +0 -1
  113. package/dist/lib/supabase.js +0 -11
  114. package/dist/lib/supabase.js.map +0 -1
  115. package/dist/lib/twilio.d.ts +0 -7
  116. package/dist/lib/twilio.d.ts.map +0 -1
  117. package/dist/lib/twilio.js +0 -34
  118. package/dist/lib/twilio.js.map +0 -1
  119. package/dist/lib/vapi.d.ts +0 -4
  120. package/dist/lib/vapi.d.ts.map +0 -1
  121. package/dist/lib/vapi.js +0 -59
  122. package/dist/lib/vapi.js.map +0 -1
  123. package/dist/mcp-server.d.ts +0 -3
  124. package/dist/mcp-server.d.ts.map +0 -1
  125. package/dist/mcp-server.js +0 -177
  126. package/dist/mcp-server.js.map +0 -1
  127. package/dist/types/index.d.ts +0 -104
  128. package/dist/types/index.d.ts.map +0 -1
  129. package/dist/types/index.js +0 -3
  130. package/dist/types/index.js.map +0 -1
package/.env.example CHANGED
@@ -1,41 +1,18 @@
1
- # Supabase
2
- SUPABASE_URL=https://your-project.supabase.co
3
- SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
1
+ # Telegram
2
+ TELEGRAM_BOT_TOKEN=
4
3
 
5
- # Twilio
6
- TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
7
- TWILIO_AUTH_TOKEN=your-auth-token
8
- TWILIO_VERIFY_SERVICE_SID=VAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
9
- TWILIO_NUMBER_FLAGSHIP=+1xxxxxxxxxx
10
- TWILIO_NUMBER_CASUAL=
11
- TWILIO_NUMBER_KINK=
12
- TWILIO_NUMBER_ADVENTURE=
13
- TWILIO_NUMBER_OPEN_POLY=
4
+ # Redis
5
+ REDIS_URL=redis://localhost:6379
14
6
 
15
- # Vapi (voice AI v0.1)
16
- VAPI_API_KEY=your-vapi-key
17
- VAPI_INTAKE_ASSISTANT_ID=your-intake-assistant-id
18
- VAPI_CONSENT_ASSISTANT_ID=your-consent-assistant-id
19
-
20
- # Anthropic
7
+ # Anthropic (for Claude Code subprocess)
21
8
  ANTHROPIC_API_KEY=sk-ant-xxxxx
22
9
 
23
- # OpenAI (embeddings)
24
- OPENAI_API_KEY=sk-xxxxx
25
-
26
- # Deepgram (transcription)
27
- DEEPGRAM_API_KEY=your-deepgram-key
28
-
29
- # Cloudflare R2
30
- CLOUDFLARE_ACCOUNT_ID=your-account-id
31
- R2_ACCESS_KEY_ID=your-access-key
32
- R2_SECRET_ACCESS_KEY=your-secret-key
33
- R2_BUCKET_NAME=meet-the-one-audio
10
+ # Claude Code OAuth token (alternative auth)
11
+ CLAUDE_CODE_OAUTH_TOKEN=
34
12
 
35
- # Inngest
36
- INNGEST_EVENT_KEY=your-event-key
37
- INNGEST_SIGNING_KEY=your-signing-key
13
+ # BlueBubbles (iMessage delivery)
14
+ BLUEBUBBLES_URL=http://localhost:1234
15
+ BLUEBUBBLES_PASSWORD=yourpassword
38
16
 
39
- # App
40
- APP_URL=http://localhost:3000
41
- PORT=3000
17
+ # System phone number (for iMessage sender identity)
18
+ SYSTEM_PHONE_NUMBER=+1XXXXXXXXXX
package/SPEC.md ADDED
@@ -0,0 +1,202 @@
1
+ # Meet The One AI — Product Spec
2
+
3
+ **North star:** Life as adventure. Expand the journey. Soul x-ray at global scale.
4
+
5
+ ---
6
+
7
+ ## The Problem
8
+
9
+ Dating apps are slot machines. Swipe, match, ghost, repeat. The mechanism is engineered for engagement, not connection.
10
+
11
+ The real problem: **compatibility is complex and humans are bad at self-knowledge.** People say they want one thing, respond to another, need a third. A 30-question quiz can't map that. 1000 swipes can't either.
12
+
13
+ What could: an agent that actually knows you — not your curated self, your real self — watches how you respond, and works on your behalf.
14
+
15
+ ---
16
+
17
+ ## The Vision
18
+
19
+ Phone = identity anchor. Soul x-ray. Unconscious psyche captured through conversation, compacted into identity, matched globally.
20
+
21
+ **No photos. No swiping. No appearance data at any point.**
22
+
23
+ Introduction via system-initiated contact. The iMessage blue bubble IS the introduction — it feels like a person thought of you.
24
+
25
+ ---
26
+
27
+ ## The Product
28
+
29
+ An AI matchmaker that operates as your personal agent.
30
+
31
+ Not a dating app. Not a chatbot. An agent — a Claude Code instance running on your behalf — that:
32
+
33
+ 1. Gets to know your real inner world through projective conversation (not a form)
34
+ 2. Captures the unconscious self: what you avoid, what lights you up, what scares you
35
+ 3. Compacts everything into a dense identity with worldview anchors and modality weights
36
+ 4. Matches globally across profiles — vector similarity + hard worldview gates
37
+ 5. Reaches out directly via iMessage when it finds your person
38
+
39
+ **The experience:**
40
+ - You talk to your agent. It asks real questions — projective, not direct.
41
+ - It listens for what you don't say as much as what you do.
42
+ - When it finds a candidate: blue bubble. "I found someone."
43
+ - You never see a profile grid. You never swipe.
44
+ - You either get introduced to someone real, or you don't hear from your agent that day.
45
+
46
+ ---
47
+
48
+ ## Architecture — cc-tg Pattern
49
+
50
+ Every user has a **persistent Claude Code subprocess** as their intake and matchmaker agent.
51
+
52
+ ```
53
+ User (Telegram)
54
+ └── Their personal Claude Code session
55
+ └── MCP tools (soul x-ray domain)
56
+ ├── create_profile (phone_number required — identity anchor)
57
+ ├── log_intake_response (question, response, modality)
58
+ ├── update_worldview (dangerous/adventurous, good/bad)
59
+ ├── get_soul_profile (completeness score + full identity)
60
+ ├── send_intro_message (BlueBubbles → iMessage blue bubble)
61
+ ├── schedule_introduction_call
62
+ ├── request_match / respond_to_match
63
+ └── get_matched_pairs
64
+
65
+ Matching Engine (separate process, Inngest)
66
+ └── Runs when identity updated
67
+ └── pgvector search → worldview hard filter → LLM validation
68
+ └── On match confirmed: initiate iMessage introduction to both phones
69
+ ```
70
+
71
+ ---
72
+
73
+ ## The Big Sorts (Non-Negotiable)
74
+
75
+ Two questions split the user population into incompatible universes:
76
+
77
+ 1. **Is the world fundamentally a dangerous place or an adventurous place?**
78
+ 2. **Do you think people are fundamentally good or fundamentally bad?**
79
+
80
+ A person who answers dangerous + bad will not be matched with someone who answers adventurous + good. This is a hard gate in the matching engine — not a soft preference.
81
+
82
+ ---
83
+
84
+ ## Intake — Soul X-Ray
85
+
86
+ The intake agent NEVER asks direct questions. It reaches for the unconscious.
87
+
88
+ **Projective prompts:**
89
+ - "Close your eyes. Imagine a big white empty space. What's the first thing that comes to mind?"
90
+ - "Imagine a big empty black space. What do you feel?"
91
+ - "Tell me about a moment you felt completely free."
92
+ - "What are you most afraid of in another person?"
93
+
94
+ **Behavioral signals (gathered indirectly):**
95
+ - Do they travel? Do they have a passport?
96
+ - Are they a yes-person or a no-person?
97
+ - How do they text — punctuation style, response latency, emoji?
98
+
99
+ **The 4AM principle:** Encourage voice messages late at night, when defenses are down and the real self speaks. Every voice session is transcribed and analyzed as signal.
100
+
101
+ ---
102
+
103
+ ## Introduction Flow — The Blue Bubble
104
+
105
+ When two users match and both consent:
106
+
107
+ ```
108
+ System → iMessage to User A:
109
+ "hey [name] — i've been thinking about this.
110
+ i found someone. their name is [name].
111
+ i'm not going to tell you much yet — that would ruin it.
112
+ what i'll say: the way they see the world matches something in you.
113
+ if you want the introduction: reply 'yes'. no pressure."
114
+
115
+ System → iMessage to User B (same framing, different words)
116
+
117
+ On mutual yes → system texts both their numbers to each other
118
+ ```
119
+
120
+ The blue bubble feels human. It feels like a person thought of you. That's intentional.
121
+
122
+ ---
123
+
124
+ ## Compatibility Model
125
+
126
+ Analysis pipeline extracts signal across 4 domains + worldview:
127
+
128
+ | Domain | Key dimensions |
129
+ |--------|---------------|
130
+ | **Relationships** | Attachment style, trust pattern, conflict mode |
131
+ | **Desire** | Expressed + inferred, kink-vanilla spectrum, shame-sovereignty |
132
+ | **Money** | Scarcity-abundance orientation, risk tolerance, ambition |
133
+ | **Health** | Energy pattern, physicality orientation |
134
+ | **Worldview** | World danger/adventure, people good/bad, VALS type, Eight Games |
135
+
136
+ Matching uses pgvector (per-modality embeddings) with worldview hard gates and LLM validation.
137
+
138
+ ---
139
+
140
+ ## Technical Stack
141
+
142
+ - **TypeScript / Node.js** on Railway
143
+ - **Redis** — agent sessions, profiles, intake state
144
+ - **Supabase + pgvector** — identity storage, vector matching
145
+ - **Claude API** — per-user agent sessions (cc-tg pattern)
146
+ - **Telegram bot** — primary intake interface
147
+ - **BlueBubbles** — iMessage delivery (blue bubble introductions)
148
+ - **Inngest** — async pipeline orchestration
149
+ - **Vapi / Twilio** — outbound voice intake calls
150
+ - **Deepgram** — transcription
151
+ - **Cloudflare R2** — audio + transcript storage
152
+ - **MCP server** — soul x-ray tools available to each agent
153
+
154
+ ---
155
+
156
+ ## Monetization
157
+
158
+ | Tier | Price | Description |
159
+ |------|-------|-------------|
160
+ | **Agent** | $39/month | Personal intake agent, soul x-ray, up to 3 introductions/month |
161
+ | **Priority** | $79/month | Faster matching, agent works daily, 10 introductions/month |
162
+ | **Concierge** | $149/month | Human curator reviews selections, white-glove introductions |
163
+
164
+ ---
165
+
166
+ ## Regulatory + Ethics
167
+
168
+ **Disclosure:** Users know they're talking to an AI. Stated at signup and in every conversation.
169
+
170
+ **Real matches:** The introductions are between real people. The agent facilitates; the relationship is human.
171
+
172
+ **No appearance data:** No photos, no physical descriptions used in matching.
173
+
174
+ **Portable identity:** Users can export their full identity profile at any time (GDPR-compliant).
175
+
176
+ ---
177
+
178
+ ## MVP Scope
179
+
180
+ 1. Telegram bot interface
181
+ 2. Per-user Claude Code session (cc-tg architecture)
182
+ 3. Soul x-ray intake with projective prompts
183
+ 4. MCP server with 11 tools (profile, intake, worldview, iMessage, matching)
184
+ 5. BlueBubbles iMessage delivery for introductions
185
+ 6. Introduction flow (consent → mutual yes → exchange numbers)
186
+ 7. Stripe: $39/month tier only
187
+
188
+ **Success metric:** 20 users, 3 successful blue-bubble introductions in first month.
189
+
190
+ ---
191
+
192
+ ## Long-term Vision
193
+
194
+ The agent becomes a relationship intelligence layer:
195
+
196
+ - **Pre-match:** knows what you need before you do
197
+ - **Introduction:** blue bubble. Feels real because it is.
198
+ - **Early dating:** available for advice, pattern-spotting
199
+ - **Relationship:** health check-ins, communication coaching
200
+ - **Breakup support:** held full context, knows the whole story
201
+
202
+ The agent that watched you fall in love is the one you trust when it gets hard.
package/USER_SPEC.md ADDED
@@ -0,0 +1,201 @@
1
+ # Meet The One AI — User Spec
2
+
3
+ ---
4
+
5
+ ## User Archetypes
6
+
7
+ ### The Done-With-Apps Woman, 34
8
+ Three years on Hinge, nothing real. Smart, successful, knows exactly what she's doing wrong (nothing) and what the apps are doing wrong (everything). Willing to try something radically different because the current approach is clearly not working.
9
+
10
+ **What she needs:** Someone working FOR her, not just showing her options.
11
+ **Retention driver:** When her agent says "I'm not introducing you to anyone this week — nobody I've seen is worth your time," she feels represented.
12
+ **iMessage moment:** Blue bubble at 9pm. "I found someone." She stops scrolling.
13
+
14
+ ### The Serious Man, 41
15
+ Done with casual. Has a career, has a life, wants a real partner. Dating apps feel like shopping. He wants a process that respects his time and intelligence.
16
+
17
+ **What he needs:** Quality over volume. Agent that filters aggressively.
18
+ **Retention driver:** The introduction when it happens feels earned and intentional.
19
+ **iMessage moment:** The message doesn't explain itself. "their name is Maya. the way she sees the world matches something in you." He replies yes without overthinking it.
20
+
21
+ ### The Self-Aware Rebuilder, 29
22
+ Out of a serious relationship. Knows she has patterns to break. Wants help seeing herself clearly before she repeats the same mistakes.
23
+
24
+ **What she needs:** An agent that asks the uncomfortable questions. Help understanding herself.
25
+ **Retention driver:** "Your agent noticed something" — when the agent surfaces a pattern she hadn't seen, she trusts it more.
26
+ **iMessage moment:** She's not even looking. Blue bubble arrives. The timing feels right.
27
+
28
+ ---
29
+
30
+ ## Conversation Design — The Soul X-Ray
31
+
32
+ The intake conversation is the most important product moment. It sets the container for everything that follows.
33
+
34
+ **What makes it different:**
35
+ The agent never asks what you're looking for in a partner. It asks projective questions that reach past the curated self.
36
+
37
+ **Opening:**
38
+ > "Hi. I'm not going to ask you to fill out a profile. I want to actually know you — not your stats. Let's start here: tell me something about yourself that most people get wrong."
39
+
40
+ **What the agent listens for:**
41
+ - How they talk (pace, directness, humor or lack of it)
42
+ - What they immediately prioritize (the first complaint reveals the first value)
43
+ - Self-awareness level (do they take any responsibility? all of it? none?)
44
+ - Emotional vocabulary
45
+ - What they avoid
46
+
47
+ **The arc (first session, 15-25 exchanges):**
48
+ 1. One projective image prompt ("white space / black space")
49
+ 2. A memory of feeling free
50
+ 3. A fear about another person
51
+ 4. What went wrong before — the pattern, not the story
52
+ 5. The two big worldview questions (world: dangerous/adventurous, people: good/bad)
53
+ 6. Behavioral signals woven in naturally
54
+ 7. Closing: "I'll reach out when I find your match. You'll hear from me — via text."
55
+
56
+ **The 4AM principle:**
57
+ > "If it's late and you can't sleep and something real is on your mind — send me a voice message. That's when I learn the most about you."
58
+
59
+ ---
60
+
61
+ ## Introduction Experience — The Blue Bubble
62
+
63
+ When the agent finds a match, both users receive an iMessage. Not a Telegram message. Not an email. A blue bubble — from a real phone number.
64
+
65
+ **Message to User A:**
66
+ ```
67
+ hey [name] —
68
+
69
+ i've been thinking about this.
70
+
71
+ i found someone. their name is [name].
72
+ i'm not going to tell you much yet — that would ruin it.
73
+ what i'll say: the way they see the world matches something in you.
74
+
75
+ if you want the introduction: reply "yes"
76
+ if you want to pass: reply "no"
77
+
78
+ no pressure either way.
79
+
80
+ — your matchmaker
81
+ ```
82
+
83
+ **Why iMessage:**
84
+ The blue bubble is an artifact of human communication. It triggers the same recognition as a text from a friend. The introduction lands differently when it arrives this way.
85
+
86
+ **On mutual yes:**
87
+ Both users receive each other's phone numbers with a note: "you both said yes. the rest is yours."
88
+
89
+ The agent steps back. The relationship is human from here.
90
+
91
+ ---
92
+
93
+ ## Agent Behavior — Daily
94
+
95
+ ```
96
+ When user has an active profile:
97
+ 1. Check for new potential matches in the pool
98
+ 2. Run worldview compatibility check (hard filter first)
99
+ 3. Run vector similarity against their soul profile
100
+ 4. If high-confidence match (score > 0.8): initiate introduction sequence
101
+ 5. If no match: silence. Silence is correct. Better than noise.
102
+
103
+ When user sends a message:
104
+ 1. Log as intake signal
105
+ 2. Ask one projective or behavioral question
106
+ 3. Update soul profile completeness
107
+ 4. When ready: begin matching
108
+
109
+ When match is confirmed:
110
+ 1. Send iMessage to both phones
111
+ 2. Wait for consent replies
112
+ 3. On mutual yes: exchange numbers via iMessage
113
+ 4. Log introduction outcome
114
+ ```
115
+
116
+ ---
117
+
118
+ ## What the Agent Builds
119
+
120
+ Through intake, the agent compacts a dense identity:
121
+
122
+ ```
123
+ {
124
+ worldview: {
125
+ world: "adventurous" | "dangerous",
126
+ people: "good" | "bad"
127
+ },
128
+ relationships: {
129
+ attachment_style: "secure" | "anxious" | "avoidant",
130
+ trust_pattern: string,
131
+ conflict_mode: string
132
+ },
133
+ desire: {
134
+ expressed: [...],
135
+ inferred: [...],
136
+ kink_vanilla_spectrum: 0-1
137
+ },
138
+ money: {
139
+ scarcity_abundance: 0-1,
140
+ risk_tolerance: 0-1
141
+ },
142
+ health: {
143
+ energy_pattern: string
144
+ },
145
+ behavioral: {
146
+ passport: boolean,
147
+ yes_or_no_person: "yes" | "no",
148
+ energy_level: "depleted" | "steady" | "hot"
149
+ },
150
+ completeness_score: 0-1,
151
+ ready_for_matching: boolean
152
+ }
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Feedback Loops
158
+
159
+ Every interaction feeds the agent's model:
160
+
161
+ | Event | Signal captured |
162
+ |-------|----------------|
163
+ | User accepts intro | What about this match triggered yes? |
164
+ | User declines intro | What was the specific objection? |
165
+ | Introduction goes well | What resonated? |
166
+ | Introduction dies | What killed it? |
167
+ | User sends 4AM voice message | High-trust signal — analyze deeply |
168
+ | User asks for pause | "I need a break" → agent goes quiet, sets check-in |
169
+
170
+ ---
171
+
172
+ ## Edge Cases
173
+
174
+ **User wants to pause:** "I need a break." → Agent acknowledges, sets a check-in date, goes quiet. No pressure.
175
+
176
+ **User is clearly not ready:** Agent says so directly.
177
+ > "I want to be honest — from what you've shared, I don't think you're ready for an introduction right now. I think you're still processing [X]. That's not a judgment. When you're ready, I'll be here."
178
+
179
+ This is the feature that builds trust. An agent that protects you from yourself.
180
+
181
+ **Match goes badly:** Agent is available immediately.
182
+ > "What happened? Tell me."
183
+ Then uses the story to sharpen the profile, not just sympathize.
184
+
185
+ **Two users both match with the same person:** Agent with stronger compatibility score gets the introduction. The other agent tells their user:
186
+ > "I almost introduced you to someone this week. I decided to wait. Here's why."
187
+ Transparency builds trust.
188
+
189
+ ---
190
+
191
+ ## Success Metrics
192
+
193
+ | Metric | Target |
194
+ |--------|--------|
195
+ | Onboarding completion (profile + worldview + 10 intake exchanges) | >80% |
196
+ | D30 retention | >65% |
197
+ | Introduction acceptance rate | >70% (agent should not offer bad matches) |
198
+ | Post-intro continued conversation | >60% |
199
+ | "Did your agent understand you?" (monthly survey) | >80% yes |
200
+ | Real-world meeting rate | >30% of accepted intros |
201
+ | Referral rate | >40% ("I have to tell you about this thing") |
package/package.json CHANGED
@@ -1,17 +1,24 @@
1
1
  {
2
2
  "name": "@gonzih/meet-the-one-ai",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "AI-powered dating service using Claude Code agents",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
7
- "bin": { "meet-the-one-ai": "dist/index.js" },
7
+ "bin": {
8
+ "meet-the-one-ai": "dist/index.js"
9
+ },
8
10
  "scripts": {
9
11
  "dev": "tsx watch src/index.ts",
10
12
  "build": "tsc",
11
13
  "start": "node dist/index.js",
12
14
  "typecheck": "tsc --noEmit"
13
15
  },
14
- "keywords": ["dating", "ai", "claude", "telegram"],
16
+ "keywords": [
17
+ "dating",
18
+ "ai",
19
+ "claude",
20
+ "telegram"
21
+ ],
15
22
  "author": "",
16
23
  "license": "ISC",
17
24
  "devDependencies": {
package/src/agent.ts CHANGED
@@ -8,25 +8,39 @@ import { Redis } from "ioredis";
8
8
  const __dirname = dirname(fileURLToPath(import.meta.url));
9
9
  const redis = new Redis(process.env.REDIS_URL ?? "redis://localhost:6379");
10
10
 
11
- const SYSTEM_PROMPT =
12
- "You are a compassionate AI matchmaker helping people find meaningful connections. " +
13
- "Use the dating tools to manage profiles and matches. " +
14
- "Be warm, curious, and insightful. Ask about values, life goals, and what matters to them — not just surface traits. " +
15
- "When a user first arrives, help them create their profile by asking thoughtful questions. " +
16
- "Proactively look for compatible matches and suggest them with care.";
11
+ const SYSTEM_PROMPT = `You are the intake agent for meet-the-one.ai. Your job: understand this person's real inner world.
12
+
13
+ You have access to MCP tools. For EVERY message the user sends, call log_message first, then respond.
14
+ As you learn things about them, call update_soul_profile to capture insights.
15
+
16
+ NEVER ask "what are you looking for in a partner?" use projective prompts:
17
+ - "Imagine a big white empty space. What's the first thing that comes to mind?"
18
+ - "Tell me about a moment you felt completely free."
19
+ - "Is the world fundamentally dangerous or adventurous?"
20
+ - "Are people fundamentally good or bad?"
21
+
22
+ The last two questions are critical — call set_worldview when you have answers.
23
+ These determine who can be matched with whom. Non-negotiable.
24
+
25
+ Encourage 4AM voice recordings. That's when defenses are down.
26
+ Log everything. Even silences. Even one-word replies.
27
+
28
+ When soul_profile completeness > 0.7, tell them: "I'll reach out when I find your match. You'll get a text."`.trim();
17
29
 
18
30
  async function getMcpConfigPath(userId: string): Promise<string> {
19
- const configPath = join(tmpdir(), `mcp-dating-${userId}.json`);
20
- // In dev use src path; in prod use compiled dist path
31
+ const configPath = join(tmpdir(), `mcp-intake-${userId}.json`);
21
32
  const mcpServerPath = join(__dirname, "../dist/mcp-server.js");
22
33
  const config = {
23
34
  mcpServers: {
24
- dating: {
35
+ intake: {
25
36
  command: "node",
26
37
  args: [mcpServerPath],
27
38
  env: {
28
39
  USER_ID: userId,
29
40
  REDIS_URL: process.env.REDIS_URL ?? "redis://localhost:6379",
41
+ TELEGRAM_BOT_TOKEN: process.env.TELEGRAM_BOT_TOKEN ?? "",
42
+ BLUEBUBBLES_URL: process.env.BLUEBUBBLES_URL ?? "",
43
+ BLUEBUBBLES_PASSWORD: process.env.BLUEBUBBLES_PASSWORD ?? "",
30
44
  },
31
45
  },
32
46
  },
@@ -37,11 +51,13 @@ async function getMcpConfigPath(userId: string): Promise<string> {
37
51
 
38
52
  export async function sendMessage(userId: string, message: string): Promise<string> {
39
53
  const mcpConfigPath = await getMcpConfigPath(userId);
40
- const sessionId = await redis.get(`dating:session:${userId}`);
54
+ const sessionId = await redis.get(`users:${userId}:session_id`);
41
55
 
42
56
  const args = [
43
57
  "--print",
44
58
  "--dangerously-skip-permissions",
59
+ "--input-format",
60
+ "stream-json",
45
61
  "--output-format",
46
62
  "stream-json",
47
63
  "--mcp-config",
@@ -51,7 +67,6 @@ export async function sendMessage(userId: string, message: string): Promise<stri
51
67
  if (sessionId) {
52
68
  args.push("--resume", sessionId);
53
69
  } else {
54
- // Prepend system context on first message
55
70
  args.push("--system-prompt", SYSTEM_PROMPT);
56
71
  }
57
72
 
@@ -94,13 +109,19 @@ export async function sendMessage(userId: string, message: string): Promise<stri
94
109
 
95
110
  proc.on("close", async (code) => {
96
111
  if (resultSessionId) {
97
- await redis.set(`dating:session:${userId}`, resultSessionId).catch(console.error);
112
+ await redis.set(`users:${userId}:session_id`, resultSessionId).catch(console.error);
98
113
  }
114
+ // Update lastActiveAt
115
+ const metaData = await redis.get(`users:${userId}:meta`).catch(() => null);
116
+ const meta = metaData ? (JSON.parse(metaData) as Record<string, unknown>) : {};
117
+ meta.lastActiveAt = new Date().toISOString();
118
+ await redis.set(`users:${userId}:meta`, JSON.stringify(meta)).catch(console.error);
119
+
99
120
  if (!outputText && code !== 0) {
100
121
  console.error(`[agent:${userId}] exited ${code}: ${stderr}`);
101
122
  reject(new Error(`Claude exited with code ${code}`));
102
123
  } else {
103
- resolve(outputText || "I'm here to help you find love! What would you like to explore?");
124
+ resolve(outputText || "I'm here. Tell me more.");
104
125
  }
105
126
  });
106
127
 
@@ -108,7 +129,6 @@ export async function sendMessage(userId: string, message: string): Promise<stri
108
129
  reject(new Error(`Failed to spawn claude: ${err.message}`));
109
130
  });
110
131
 
111
- // Send user message via stdin in stream-json format
112
132
  const input =
113
133
  JSON.stringify({
114
134
  type: "user",