PRD 002 — Awesome Texting Experience (Q0)
Status: Draft — answers picortex-adb / Q0 of the prototype-options brainstorm
Owner: Jacob
Date: 2026-04-23
This PRD defines what "awesome texting experience" means in measurable terms. It is the product target every architecture option (Options 1-5 in the brainstorm) must hit. If an option can't hit these criteria, the option is out. Supersedes the product section of PRD 001 (which was architecture-first and scoped around dev surfaces).
1. Vision (one paragraph)
Jacob adds a bot to any ongoing texting discussion — iMessage via Linq OR OpenChat — and it works pretty well. It feels native on the platform (replies threaded, reactions supported, typing indicator, not spammy in groups). It has access to whatever Jacob has told it about himself, but private information never leaks from a 1:1 DM into a group without Jacob's explicit out-of-band approval. When a group member asks something that needs private data ("is Jacob free Tuesday?"), the bot pauses, DMs Jacob privately with the proposed disclosure, waits for approval, and only then answers in the group — with a clear audit trail of what got shared and why.
2. The product in one test
The single test that proves we've shipped it:
A friend adds the bot to a group text with three other people. Over the next hour:
- The bot stays quiet during normal chatter.
- When someone @mentions it with a question that's public-friendly, it replies usefully in under 15 seconds, in-thread.
- When someone asks "hey, is Jacob free to meet this week?", the bot says "let me check" in the group, DMs Jacob privately with the question + its proposed response, and only answers the group once Jacob approves.
- No one in the group sees anything from Jacob's private DM workspace, calendar, or knowledge base that Jacob didn't explicitly approve.
If this loop works end-to-end, consistently, the product is live.
3. Five pillars
P1 — Native platform feel
The bot must not feel like a web chatbot bolted onto SMS. Specifically:
- P1.1 Threading. In-thread replies preserve
reply_to_message_idwhen replying to a specific message (not just the most recent). - P1.2 Reactions. Bot reacts with tapbacks to acknowledge tasks (👍 "understood", 🤔 "thinking", ✅ "done"). Reactions on the bot trigger behaviors (⭐ save, 💡 remember, 🔖 bookmark, ❌ retract last message).
- P1.3 Typing indicator. On within 2s of inbound when the bot plans to respond; off when done.
- P1.4 Edits. If a user edits their message before the bot replies, the bot uses the latest version. After the bot replies, user edits are acknowledged but don't re-trigger.
- P1.5 Formatting. No markdown walls on iMessage. Code blocks render as quoted plain text; bullets as short dashes; long answers split across messages with context ("1/3 — ", "2/3 — ").
- P1.6 Participant changes. Bot handles add/remove/rename gracefully — notes them, doesn't panic.
- P1.7 Channel parity. Linq (iMessage) and OpenChat identical behavior. One event normalization layer.
P2 — Smart attention (not spammy)
Groups die when bots interrupt. Defaults:
- P2.1 Default mode in groups:
mentions-only— bot responds only to@bot, reply-to-bot, or/slashcommands. - P2.2 Default mode in DMs:
always— bot responds to every message. - P2.3 Upgradable in-place.
@bot louder/@bot quieter/@bot silentadjusts in-line; Jacob's-DM-only admin commands. - P2.4 Discriminator mode — optional per-chat LLM gate (from Cortex R4) that decides whether to respond to non-mentions based on topic relevance. Default OFF for groups.
- P2.5 Rate ceiling. Bot never sends > 1 message per 20 human messages in a group over any 10-minute window (hard cap, logged).
- P2.6 Silence on unclear. If a group message is ambiguous ("did you see that?"), the bot does NOT try to guess — silent.
P3 — Knowledge with boundaries (per-chat manifest)
Every chat has a knowledge_manifest defining what subsets of Jacob's world the bot may draw on. Default for a new group: nothing private. The bot has only the group's own transcript + public info.
Jacob can expand a group's manifest explicitly:
- P3.1 Granular grants. Subsets of the noos graph (specific tags, specific note-collections), specific calendar windows ("next 2 weeks only"), specific contact tags, specific files.
- P3.2 Ephemeral vs permanent. A grant can be "for this thread only" (expires when the thread dies), "for 24h", or permanent.
- P3.3 Default DM manifest: everything. 1:1 chat with Jacob = full trust.
- P3.4 Per-chat manifest is versioned and auditable. Changes log as
ManifestEventrows: who, when, what was added/removed. - P3.5 Bot discloses its boundaries on request. "What do you know about me in this chat?" → bot responds with the manifest summary.
P4 — Consent-mediated disclosure (the banger)
When the bot needs private data the chat's manifest doesn't cover, it pauses and asks Jacob out-of-band.
The loop:
- P4.1 In-group: bot replies "let me check with Jacob" within 5s. Typing indicator stays on.
- P4.2 Out-of-band DM to Jacob: within 5s of the group trigger. Message contains:
- The question as asked
- The full group context (which chat, who asked, last N messages)
- The specific private data needed ("calendar Tuesday 9am-9pm")
- A proposed response to send back to the group
- Buttons / text shortcuts:
approve,approve-subset,modify,deny+ optional reason
- P4.3 Jacob's approval has three granularities:
- "Approve exact" — send exactly the proposed response, no more
- "Approve subset" — edit the response first, then send
- "Permanent grant" — also upgrade the group's manifest so future similar asks don't need approval
- P4.4 Timeout. If Jacob doesn't respond in 10 minutes, bot tells the group "I need to check on that offline — will follow up later" and closes the loop. No indefinite waits.
- P4.5 Audit trail. Every disclosure loop logs a
DisclosureEventrow: question, source chat, destination chat, data accessed, approver, approval mode, timestamp, final message sent. - P4.6 No leak on deny. If Jacob denies, bot says "I don't have access to answer that" — does NOT say "Jacob said no" or reveal the internal loop.
- P4.7 Revocable. Jacob can retract a permanent grant at any time; next similar ask goes through approval again.
This is Cortex's R5.4-5.5 + R7 sharing bridge turned outward: instead of importing files into a chat, we're authorizing knowledge to flow from private → group at read time.
P5 — Graceful degradation
- P5.1 Tool-use failure. "I tried to check X but the tool failed — want me to try again or skip?" Never silent-swallow an error.
- P5.2 Knowledge denied. "I don't have access to that" (truthful but not oversharing).
- P5.3 Bot offline. Linq inbound still queued; when back, bot says "I was offline — here's my reply to your earlier message". Never drop inbound silently.
- P5.4 Ambiguous intent. "I'm not sure which X you mean — A or B?" Ask, don't assume.
- P5.5 Over-capacity. If the bot is saturated and Jacob's pending approvals queue is deep, it says so in the group: "I'm backed up — answer in a few minutes."
4. Latency budget
| Scenario | Target | Ceiling |
|---|---|---|
| Typing indicator appears after inbound | 2s | 5s |
| Warm 1:1 first token | 5s | 15s |
| Warm group first token (when bot decides to speak) | 10s | 20s |
| Cold provisioning (first message ever to a new chat) | 30s | 60s |
| "Let me check" ack in consent loop | 5s | 10s |
| End-to-end consent loop (group ask → Jacob approve → group reply) | 30-120s | 10 min (timeout) |
| Bot recovery from crash | 30s | 2 min |
5. Measurable success metrics
Gate these at 30 days of real use:
- M1. Jacob sends ≥ 5 messages/day to the bot (1:1) for 14 consecutive days.
- M2. Bot is in ≥ 2 real group chats (friends / family / coworkers — not test groups) for ≥ 7 days each.
- M3. ≥ 1 consent-loop successfully completed end-to-end (group ask → Jacob approve → group reply, all in audit log).
- M4. Zero unapproved private-info disclosures across all groups (audited).
- M5. p95 warm 1:1 first token ≤ 15s.
- M6. p95 warm group first token ≤ 20s.
- M7. Bot's message ratio in groups stays ≤ 1:20 vs humans over any 10-min window.
- M8. Friends in group chats describe bot as "useful" or "not annoying" in unstructured feedback (qualitative; ≥ 3 positive statements, 0 "please remove it" requests).
6. Pass/fail acceptance tests
These are the tests that must green before v0.1 ships:
- T-native. Bot replies in-thread, types typing indicator, uses tapback reactions. Verified on iMessage via Linq AND on OpenChat via its WebSocket.
- T-attention. In a 50-message group conversation where bot is NOT mentioned, bot sends 0 messages. When mentioned once, bot sends 1 reply. Over-ceiling guard triggers if bot attempts to exceed the 1:20 ratio.
- T-manifest-default. New group, default manifest. Someone asks "what's in Jacob's calendar?" — bot declines without DMing Jacob (it's not in scope for this group, and the default is deny).
- T-consent-approve. Someone asks "is Jacob free Tuesday?" in a group with calendar access not pre-authorized. Bot → "let me check". DM to Jacob within 5s with proposed response. Jacob replies "yes". Group gets the answer.
DisclosureEventlogged. - T-consent-deny. Same setup; Jacob replies "no". Group gets "I don't have access to answer that" — no hint about the DM loop.
- T-consent-timeout. Same setup; Jacob doesn't reply. After 10 min, group gets "I need to check on that offline — will follow up later".
- T-retract. Jacob reacts ❌ on a bot message in any chat. Bot deletes / retracts that message (platform-specific: iMessage edit to "[retracted]"; OpenChat actual delete).
- T-offline. Backend restarted mid-message. On recovery, bot sends "I was offline — here's my reply".
- T-parity. All tests above pass identically on Linq iMessage AND OpenChat.
7. Explicit non-goals for v0.1
- NG1. Voice memos, images, attachments beyond text. v0.2.
- NG2. Native group UI (any web UI) — 1:1 web UI OK if it falls out for free; group UI is v0.2.
- NG3. Multi-user bot operation (other people running their own picortex pointing at shared infra). v1.0+.
- NG4. Cross-channel unification ("same Jacob on Linq DM and OpenChat DM is the same context"). v0.3.
- NG5. Proactive messages from the bot (bot spontaneously texting based on calendar etc.). v0.2.
- NG6. Shared bot in both a Jacob-only DM and a group — where the DM context influences the group. v0.3.
- NG7. Fine-grained per-person-in-group policy ("Alice can ask about calendar, Bob can't"). v0.3+.
8. Open questions → traceability
| Q ticket | Question | How this PRD constrains it |
|---|---|---|
Q1 picortex-g0u |
Physical layout | Consent loop (P4) needs reliable DM delivery while group is waiting — argues against single-box failure domains. |
Q2 picortex-2b4 |
Dev surface v0.1? | Not required by any pillar. Can be deferred. |
Q3 picortex-xmd |
Workspace granularity | Per-chat matters because manifest is per-chat. Per-user would collapse manifests. |
Q4 picortex-3mk |
Agent executor | Must support deferred-response pattern (start a turn, pause for out-of-band approval, resume). claude -c -p per turn handles this cleanly; tmux REPL is awkward. |
Q5 picortex-5gi |
noos graph drop-in | Directly feeds P3 knowledge manifests. Strongly preferred. |
Q6 picortex-2qk |
Privacy threat boundary | P3 + P4 are the primary privacy features; threat model must protect both. |
Q7 picortex-qrc |
Deployment target | DM-while-group-waiting implies low-latency + always-on. Fly Machine or Hetzner win over HMA (home internet flakiness). |
Q8 picortex-f7r |
v0.1 slice | This PRD IS Q0's answer; Q8 is "which pillars + which tests are v0.1, and which are v0.2". |
9. v0.1 minimum slice (proposed — to be finalized in Q8)
Ship these first:
- P1 (native feel) — minus P1.2 reactions-to-trigger-behaviors (that's v0.2)
- P2 (attention) — mentions-only + DM always; discriminator mode deferred to v0.2
- P3 (manifests) — default-deny for groups, default-allow for DMs; granular grants deferred to v0.2
- P4 (consent loop) — approve/deny only; "approve-subset" edit + permanent-grant upgrade deferred to v0.2
- P5 (graceful degradation) — all of it
Tests that must green for v0.1: T-native, T-attention, T-manifest-default, T-consent-approve, T-consent-deny, T-consent-timeout, T-offline, T-parity.
Metrics gating v0.1 → v0.2: M1, M3, M4, M5, M7. (M2 and M8 require v0.1 in real use for 30+ days.)
10. Related
- PRD 001 — original architecture-first PRD (now provisional; this supersedes its product section)
- Prototype options — architecture options that must hit these criteria
- Piyush-era study — Option 2 candidate
- Codex session review — flagged "awesome texting experience is unpinned" as the biggest gap
- Cortex R4 (attention gating) + R5.4-R5.5 (out-of-band consent) + R7 (sharing bridge) — ancestors of P2 + P4