|
| 1 | +# Spec 012: Ourmoji Module |
| 2 | + |
| 3 | +**Status:** Draft |
| 4 | +**Author:** Ted (via Caspar's brief) |
| 5 | +**Date:** 2026-03-29 |
| 6 | +**Target:** v0.5.0+ (standalone internal module) |
| 7 | +**Access:** Restricted — select users only (Caspar + Marian initially) |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +## Overview |
| 12 | + |
| 13 | +Ourmoji is Ta-Da!'s first "secret module" — a chaos magick daily practice and dream divination experiment, built as an internal module using the modular architecture from `design/modularity.md` (Option B: Internal Module Registry). |
| 14 | + |
| 15 | +Two parts: |
| 16 | +1. **Daily Ourmoji** — log the daily emoji + reflection as a Ta-Da! event |
| 17 | +2. **Dream Experiment** — a controlled dream telepathy protocol managed entirely within Ta-Da! |
| 18 | + |
| 19 | +Philosophy: this module must be **beautiful**, **magical**, and follow the Ta-Da! ethos of "noticing, not tracking." It should feel like opening a grimoire, not filling out a form. |
| 20 | + |
| 21 | +--- |
| 22 | + |
| 23 | +## Part 1: Daily Ourmoji |
| 24 | + |
| 25 | +### What It Does |
| 26 | + |
| 27 | +Each morning, an emoji is drawn from the Sacred Set (23 curated emoji with symbolic resonance). A poetic reflection links the emoji to the moon phase, the date, and any significant days from the Wheel of the Year. |
| 28 | + |
| 29 | +Currently this happens via OpenClaw cron → WhatsApp/Telegram. Ta-Da!'s role is **not** to replace that delivery — it's to **log and display** the daily Ourmoji as a first-class event. |
| 30 | + |
| 31 | +### Data Model |
| 32 | + |
| 33 | +Entry type: `ourmoji` (new type, registered via module registry) |
| 34 | + |
| 35 | +```typescript |
| 36 | +interface OurmojiData { |
| 37 | + emoji: string; // The day's emoji |
| 38 | + reflection: string; // 2-3 sentence poetic text |
| 39 | + moonPhase: string; // e.g., "Waxing Crescent" |
| 40 | + moonIllumination: number; // 0-100 |
| 41 | + wheelOfYear?: string; // If a named day (e.g., "Beltane", "Bowie Day") |
| 42 | + wheelCategory?: string; // e.g., "Discordian", "Pagan", "Málaga" |
| 43 | + source: "manual" | "api"; // How it arrived (manual entry vs API push) |
| 44 | +} |
| 45 | +``` |
| 46 | + |
| 47 | +### UI: Ourmoji Panel |
| 48 | + |
| 49 | +A dedicated panel (not a full page — accessible from Moments or its own nav entry for enabled users): |
| 50 | + |
| 51 | +- **Today's Ourmoji** — large emoji display, reflection text, moon phase visualisation |
| 52 | +- **Calendar view** — scroll through past Ourmojis, see the emoji for each day |
| 53 | +- **Wheel of the Year** — visual representation of upcoming named days (optional, stretch goal) |
| 54 | + |
| 55 | +### API Integration |
| 56 | + |
| 57 | +Ta-Da! REST API endpoint to receive the daily Ourmoji from OpenClaw: |
| 58 | + |
| 59 | +``` |
| 60 | +POST /api/ourmoji/daily |
| 61 | +Authorization: Bearer <api-key> |
| 62 | +{ |
| 63 | + "emoji": "🐙", |
| 64 | + "reflection": "Three hearts, each pumping blue blood...", |
| 65 | + "moonPhase": "Waning Gibbous", |
| 66 | + "moonIllumination": 72, |
| 67 | + "wheelOfYear": "World Octopus Day", |
| 68 | + "date": "2026-10-08" |
| 69 | +} |
| 70 | +``` |
| 71 | + |
| 72 | +This creates an `ourmoji` entry for the authenticated user. If an entry already exists for that date, it updates rather than duplicates. |
| 73 | + |
| 74 | +### The Sacred Set |
| 75 | + |
| 76 | +The 23 curated emoji (stored as module config, not in the DB schema): |
| 77 | + |
| 78 | +``` |
| 79 | +😜 trickster/play · 😳 surprise/vulnerability · 🤩 wonder/dazzle |
| 80 | +🧠 mind/consciousness · 🐷 earthiness/appetite · 🐸 transformation/patience |
| 81 | +🦄 magic/rarity · 🐙 intelligence/adaptation · 🐳 depth/song |
| 82 | +🍀 luck/chance · 🍄 altered states/hidden networks · 🪞 reflection/truth |
| 83 | +🛸 mystery/the unknown · 🌏 wholeness/home · 🌋 eruption/creation |
| 84 | +🌊 flow/power · 🌀 chaos/spiral · 🎲 randomness/risk |
| 85 | +🔔 awakening/call · 🗝️ access/secrets · ⚰️ endings/renewal |
| 86 | +🥚 potential/beginning · 💓 pulse/life |
| 87 | +``` |
| 88 | + |
| 89 | +### Wheel of the Year |
| 90 | + |
| 91 | +The module includes a static data file of ~65 named days (see `WHEEL_OF_THE_YEAR.md` in the OpenClaw workspace). This powers: |
| 92 | +- Contextual notes in the daily reflection ("Today is also Yuri's Night 🚀") |
| 93 | +- Calendar highlights in the Ourmoji panel |
| 94 | +- Moveable feasts (lunar-dependent dates) need annual recalculation |
| 95 | + |
| 96 | +--- |
| 97 | + |
| 98 | +## Part 2: Dream Experiment |
| 99 | + |
| 100 | +### Protocol |
| 101 | + |
| 102 | +A controlled dream telepathy experiment based on the Maimonides protocol, adapted for emoji: |
| 103 | + |
| 104 | +#### Roles |
| 105 | +- **Sender** — receives a target emoji from the Sacred Set, focuses on it before sleep |
| 106 | +- **Receiver** — records their dream on waking, then guesses which emoji was sent |
| 107 | +- **Control (double receiver)** — both participants are receivers, no sender. Establishes chance baseline. |
| 108 | +- **Rest night** — no assignment. Baseline/gap night. |
| 109 | + |
| 110 | +#### Nightly Flow |
| 111 | + |
| 112 | +1. **Evening (~21:00):** Ta-Da! randomly assigns roles for the night |
| 113 | + - Conditions weighted or configured: e.g., 50% send, 30% control, 20% rest |
| 114 | + - If **send condition**: one person randomly becomes sender, the other receiver |
| 115 | + - If **control condition**: both are receivers (no sender assigned) |
| 116 | + - If **rest**: no notification sent |
| 117 | + |
| 118 | +2. **Sender notification:** "Tonight you are the Sender. Your target emoji is: 🐙. Focus on it as you fall asleep." |
| 119 | + |
| 120 | +3. **Receiver notification:** "Tonight you are the Receiver. Record your dream when you wake." |
| 121 | + - Receiver does NOT know if there is a sender (blinded) |
| 122 | + |
| 123 | +4. **Morning:** Receiver opens Ta-Da! and: |
| 124 | + - Records their dream (free text / voice transcription — links to existing Moments dream journal) |
| 125 | + - Makes their guess: picks an emoji from the Sacred Set (forced choice, 1 of 23) |
| 126 | + - Optionally rates confidence (1-5) |
| 127 | + |
| 128 | +5. **Reveal:** After the receiver submits their guess: |
| 129 | + - Show the target emoji (if send condition) or "Control night — no target" (if control) |
| 130 | + - Show hit/miss |
| 131 | + - On control nights, still show which emoji was "closest" for interest (no scoring) |
| 132 | + |
| 133 | +#### Experiment Management |
| 134 | + |
| 135 | +- **Experiment runs:** defined start/end dates, can be paused/resumed |
| 136 | +- **Randomisation seed:** stored per experiment for reproducibility |
| 137 | +- **Role assignment algorithm:** cryptographically random, but balanced over the run (roughly equal sender/receiver splits per participant) |
| 138 | +- **Blinding:** receiver never knows if it's a send or control night until after guessing |
| 139 | +- **Data locked after submission:** dream text + guess cannot be edited post-submission (scientific integrity) |
| 140 | + |
| 141 | +### Data Model |
| 142 | + |
| 143 | +New entry type: `dream-experiment` (or stored as `moment` subcategory `dream-experiment` — TBD based on modularity constraints) |
| 144 | + |
| 145 | +```typescript |
| 146 | +interface DreamExperimentEntry { |
| 147 | + experimentId: string; // Which experiment run |
| 148 | + nightDate: string; // YYYY-MM-DD |
| 149 | + condition: "send" | "control" | "rest"; |
| 150 | + role: "sender" | "receiver" | null; |
| 151 | + targetEmoji: string | null; // The emoji assigned (null for rest/control-receiver) |
| 152 | + dreamText: string | null; // Receiver's dream transcript |
| 153 | + guess: string | null; // Receiver's emoji guess |
| 154 | + guessConfidence: number | null; // 1-5 |
| 155 | + isHit: boolean | null; // guess === targetEmoji |
| 156 | + revealedAt: string | null; // ISO timestamp of when result was shown |
| 157 | + lockedAt: string | null; // ISO timestamp — no edits after this |
| 158 | +} |
| 159 | +``` |
| 160 | + |
| 161 | +### Statistics Dashboard |
| 162 | + |
| 163 | +For experiment runs: |
| 164 | +- **Hit rate** vs chance (1/23 = 4.35%) |
| 165 | +- **Binomial test** p-value (is the hit rate significantly above chance?) |
| 166 | +- **By condition:** send vs control hit rates |
| 167 | +- **By participant:** does one person receive better? |
| 168 | +- **By emoji:** are some emoji "louder" than others? |
| 169 | +- **Timeline:** cumulative hit rate over the experiment run |
| 170 | +- **Moon phase correlation:** hit rate by lunar phase (because why not) |
| 171 | + |
| 172 | +### Dream Recording UX |
| 173 | + |
| 174 | +This is the critical UX challenge. The receiver needs to: |
| 175 | +1. Record their dream (text or voice → transcript) |
| 176 | +2. Guess the emoji |
| 177 | +3. See the reveal |
| 178 | + |
| 179 | +**All in one flow, without clicking around multiple pages.** |
| 180 | + |
| 181 | +Proposed flow: |
| 182 | +1. Receiver opens Ta-Da! in the morning |
| 183 | +2. **Experiment banner** at top: "You were a Receiver last night. Record your dream to see the result." |
| 184 | +3. Tap → opens **Dream Experiment panel**: |
| 185 | + - Voice record button (large, prominent) → transcribes dream |
| 186 | + - Or text input for typing |
| 187 | + - "Submit dream" → locks the text |
| 188 | +4. **Guess screen:** Sacred Set grid (23 emoji), tap one to guess |
| 189 | + - Optional confidence slider |
| 190 | + - "Submit guess" → locks the guess |
| 191 | +5. **Reveal animation:** the target emoji appears (or "Control night — no target was sent") |
| 192 | + - Hit: celebration animation (confetti, à la Ta-Da!) |
| 193 | + - Miss: gentle, no shame — show the target, maybe a poetic note about what the connection *could* have been |
| 194 | + - Control: "No sender tonight. Your dream was pure signal from your own depths." |
| 195 | + |
| 196 | +**Dreams outside the experiment:** regular dream logging via Moments continues to work independently. The experiment panel is an overlay/flow, not a replacement. |
| 197 | + |
| 198 | +--- |
| 199 | + |
| 200 | +## Access Control |
| 201 | + |
| 202 | +Module visibility controlled by a feature flag per user: |
| 203 | + |
| 204 | +```typescript |
| 205 | +// User settings or admin config |
| 206 | +{ |
| 207 | + enabledModules: ["ourmoji"] // Array of module IDs |
| 208 | +} |
| 209 | +``` |
| 210 | + |
| 211 | +Users without `ourmoji` in their enabled modules never see the panel, nav entry, or API endpoints. This is dev privilege — no public UI to enable it. |
| 212 | + |
| 213 | +--- |
| 214 | + |
| 215 | +## File Structure (Internal Module) |
| 216 | + |
| 217 | +Following the modularity architecture (Option B): |
| 218 | + |
| 219 | +``` |
| 220 | +app/modules/ |
| 221 | + ourmoji/ |
| 222 | + index.ts # Module registration |
| 223 | + types.ts # OurmojiData, DreamExperimentEntry types |
| 224 | + config.ts # Sacred Set, Wheel of the Year data |
| 225 | + |
| 226 | + components/ |
| 227 | + OurmojiPanel.vue # Daily emoji display + calendar |
| 228 | + DreamExperimentFlow.vue # Morning recording + guess + reveal |
| 229 | + SacredSetPicker.vue # 23-emoji grid for guessing |
| 230 | + MoonPhase.vue # Moon phase visualisation |
| 231 | + ExperimentStats.vue # Statistics dashboard |
| 232 | + WheelOfYear.vue # Calendar of named days (stretch) |
| 233 | + |
| 234 | + composables/ |
| 235 | + useOurmoji.ts # Daily emoji CRUD |
| 236 | + useDreamExperiment.ts # Experiment state, role assignment, statistics |
| 237 | + useExperimentScheduler.ts # Evening assignment logic |
| 238 | + |
| 239 | + server/ |
| 240 | + api/ |
| 241 | + ourmoji/ |
| 242 | + daily.post.ts # Receive daily Ourmoji from external (OpenClaw) |
| 243 | + daily.get.ts # Get today's / historical Ourmoji |
| 244 | + experiment/ |
| 245 | + assign.post.ts # Trigger nightly assignment |
| 246 | + dream.post.ts # Submit dream recording |
| 247 | + guess.post.ts # Submit emoji guess |
| 248 | + reveal.get.ts # Get reveal for a night |
| 249 | + stats.get.ts # Experiment statistics |
| 250 | + runs.get.ts # List experiment runs |
| 251 | + runs.post.ts # Create/configure experiment run |
| 252 | +``` |
| 253 | + |
| 254 | +--- |
| 255 | + |
| 256 | +## Implementation Phases |
| 257 | + |
| 258 | +### Phase 1: Daily Ourmoji (MVP) |
| 259 | +- Entry type registration (`ourmoji`) |
| 260 | +- API endpoint to receive daily Ourmoji from OpenClaw |
| 261 | +- Simple panel showing today's emoji + reflection + moon |
| 262 | +- Calendar view of past Ourmojis |
| 263 | +- Access control (user feature flag) |
| 264 | + |
| 265 | +### Phase 2: Dream Experiment Core |
| 266 | +- Experiment run management (create, start, pause, end) |
| 267 | +- Nightly role assignment (random, blinded) |
| 268 | +- Morning flow: dream recording → guess → reveal |
| 269 | +- Data locking post-submission |
| 270 | +- Basic statistics (hit rate, p-value) |
| 271 | + |
| 272 | +### Phase 3: Polish & Delight |
| 273 | +- Moon phase visualisation |
| 274 | +- Wheel of the Year calendar view |
| 275 | +- Reveal animations (confetti on hit, gentle on miss) |
| 276 | +- Voice recording for dreams (reuse existing voice infrastructure) |
| 277 | +- Extended statistics (by emoji, by moon phase, by participant) |
| 278 | +- Dream text analysis (stretch: keyword extraction, theme matching) |
| 279 | + |
| 280 | +--- |
| 281 | + |
| 282 | +## Design Principles |
| 283 | + |
| 284 | +1. **Magical, not clinical** — this is a grimoire, not a lab notebook. Beautiful typography, moon imagery, the Sacred Set displayed as sacred objects. |
| 285 | +2. **Rigorous where it counts** — blinding, randomisation, locked data, statistical tests. The magic is real AND the science is real. |
| 286 | +3. **Frictionless morning flow** — one tap from waking to dream recorded. Voice first. The fewer taps between pillow and transcript, the better the data. |
| 287 | +4. **Shared ritual** — this is for two people. The UI should feel intimate, not social-media-ish. No leaderboards. Just two people and the space between them. |
| 288 | +5. **Ta-Da! philosophy** — noticing, not tracking. The experiment celebrates the dream, not the hit rate. A miss is still a dream worth having. |
| 289 | + |
| 290 | +--- |
| 291 | + |
| 292 | +## Open Questions |
| 293 | + |
| 294 | +1. **Entry type vs subcategory?** Should `ourmoji` and `dream-experiment` be new entry types (requiring module registry) or subcategories under `moment`? New types are cleaner but require the modularity work. |
| 295 | +2. **Notification delivery:** How does Ta-Da! send the evening "you are the sender" notification? Push notification (PWA)? Or delegate to OpenClaw/WhatsApp? |
| 296 | +3. **Multi-user experiment state:** The experiment links two users. How is this modeled? A shared `experiment_runs` table with participant IDs? Or something simpler? |
| 297 | +4. **Wheel of the Year data source:** Static JSON in the module? Or fetched from the OpenClaw workspace dynamically? |
| 298 | +5. **Voice recording reuse:** Can we reuse the existing `VoiceRecorder` component from v0.3.0, or does the dream flow need a custom variant? |
| 299 | + |
| 300 | +--- |
| 301 | + |
| 302 | +*"The emoji is Glycon — obviously arbitrary, powerful anyway."* |
| 303 | + |
| 304 | +*Spec drafted by Ted, 2026-03-29. Based on Caspar's voice brief + Marian's original question (2026-03-15) + Maimonides dream telepathy protocol.* |
0 commit comments