Scenario
Real product feedback exists on Reddit — buried in search results and comments. This job searches for mentions, creates Mavera personas mirroring the subreddit population (frustrated newcomer, power user, comparison shopper), then runs a Focus Group. Comparing real feedback to synthetic responses validates persona accuracy.Architecture
Code
import os, requests, time
# --- Auth setup same as Job 1 ---
PRODUCT = "Notion"
# 1. Search Reddit for product mentions
r = requests.get(f"{RD}/search", headers=RD_H,
params={"q": PRODUCT, "sort": "relevance", "limit": 50, "type": "link", "raw_json": 1})
r.raise_for_status()
results = [p["data"] for p in r.json()["data"]["children"]]
real_feedback = []
for post in results:
if post.get("selftext") or post.get("title"):
real_feedback.append({"title": post["title"], "text": post.get("selftext","")[:600],
"subreddit": post.get("subreddit",""), "score": post.get("score",0)})
if post.get("num_comments", 0) > 5:
cr = requests.get(f"{RD}/comments/{post['id']}", headers=RD_H,
params={"limit": 5, "depth": 1, "sort": "top", "raw_json": 1})
if cr.ok and len(cr.json()) > 1:
for c in cr.json()[1]["data"]["children"]:
body = c.get("data",{}).get("body","")
if body and body not in ("[removed]","[deleted]"):
real_feedback.append({"title": f"Re: {post['title']}", "text": body[:400],
"subreddit": post.get("subreddit",""), "score": c["data"].get("score",0)})
time.sleep(0.7)
# 2. Create subreddit-demographic personas
PERSONAS = [
{"name": f"Frustrated {PRODUCT} Newcomer", "desc": f"New to {PRODUCT}, overwhelmed. Compares to simpler alternatives. Frustrated, seeks validation."},
{"name": f"{PRODUCT} Power User", "desc": f"Uses {PRODUCT} for everything. Builds templates. Enthusiastic, slightly defensive of the product."},
{"name": "Comparison Shopper", "desc": f"Evaluating {PRODUCT} vs Obsidian, Coda, Airtable. Analytical, price-sensitive, feature-focused."},
{"name": "Team Lead / Manager", "desc": f"Rolled out {PRODUCT} to a team. Cares about adoption friction, onboarding, per-seat pricing."},
]
persona_ids = []
for p in PERSONAS:
created = requests.post(f"{MV_BASE}/personas", headers=MV_H, json={
"name": f"Reddit: {p['name']}", "description": p["desc"],
"psychographic": {"source": "reddit_search", "product": PRODUCT},
}).json()
persona_ids.append({"id": created["id"], "name": p["name"]}); time.sleep(0.3)
# 3. Focus Group
fg = requests.post(f"{MV_BASE}/focus-groups", headers=MV_H, json={
"name": f"Reddit Mirror: {PRODUCT} Feedback",
"persona_ids": [p["id"] for p in persona_ids],
"questions": [
f"What was your first impression of {PRODUCT}?",
f"What is the biggest problem you have with {PRODUCT} right now?",
f"If you switched away from {PRODUCT}, what would you switch to and why?",
f"What one feature would you add to {PRODUCT}?",
],
"responses_per_persona": 2,
}).json()
for _ in range(20):
time.sleep(5)
data = requests.get(f"{MV_BASE}/focus-groups/{fg['id']}", headers=MV_H).json()
if data.get("status") == "completed": break
for resp in data.get("responses", []):
name = next((p["name"] for p in persona_ids if p["id"] == resp.get("persona_id")), "?")
print(f"[{name}] Q: {resp.get('question','')[:80]}")
print(f" A: {resp.get('answer','')[:300]}\n")
print(f"\nREAL REDDIT (top 3 by score):")
for fb in sorted(real_feedback, key=lambda x: -x["score"])[:3]:
print(f"[/r/{fb['subreddit']}] (score: {fb['score']}) {fb['title'][:80]}")
print(f" {fb['text'][:200]}\n")
// --- Auth setup same as Job 1 ---
const PRODUCT = "Notion";
// 1. Search
const results = (await (await fetch(
`${RD}/search?q=${encodeURIComponent(PRODUCT)}&sort=relevance&limit=50&type=link&raw_json=1`,
{ headers: RD_H })).json()).data.children.map(p => p.data);
const realFeedback = [];
for (const post of results) {
if (post.selftext || post.title)
realFeedback.push({ title: post.title, text: (post.selftext||"").slice(0,600),
subreddit: post.subreddit, score: post.score || 0 });
if ((post.num_comments||0) > 5) {
const cr = await fetch(`${RD}/comments/${post.id}?limit=5&depth=1&sort=top&raw_json=1`, { headers: RD_H });
if (cr.ok) for (const c of ((await cr.json())[1]?.data?.children || [])) {
const body = c.data?.body || "";
if (body && body !== "[removed]" && body !== "[deleted]")
realFeedback.push({ title: `Re: ${post.title}`, text: body.slice(0,400),
subreddit: post.subreddit, score: c.data?.score || 0 });
}
await new Promise(r => setTimeout(r, 700));
}
}
// 2. Personas
const PERSONAS = [
{ name: `Frustrated ${PRODUCT} Newcomer`, desc: `New, overwhelmed. Compares to simpler alternatives.` },
{ name: `${PRODUCT} Power User`, desc: `Uses for everything. Builds templates. Enthusiastic.` },
{ name: "Comparison Shopper", desc: `Evaluating vs Obsidian, Coda, Airtable. Analytical.` },
{ name: "Team Lead / Manager", desc: `Team rollout. Adoption friction, onboarding, pricing.` },
];
const personaIds = [];
for (const p of PERSONAS) {
const created = await fetch(`${MV_BASE}/personas`, { method: "POST", headers: MV_H,
body: JSON.stringify({ name: `Reddit: ${p.name}`, description: p.desc,
psychographic: { source: "reddit_search", product: PRODUCT } }),
}).then(r => r.json());
personaIds.push({ id: created.id, name: p.name });
await new Promise(r => setTimeout(r, 300));
}
// 3. Focus Group
const fg = await fetch(`${MV_BASE}/focus-groups`, { method: "POST", headers: MV_H,
body: JSON.stringify({
name: `Reddit Mirror: ${PRODUCT}`, persona_ids: personaIds.map(p => p.id),
questions: [`First impression of ${PRODUCT}?`, `Biggest problem with ${PRODUCT}?`,
`If you switched, what to and why?`, `One feature to add?`],
responses_per_persona: 2,
}),
}).then(r => r.json());
let data; for (let i = 0; i < 20; i++) {
await new Promise(r => setTimeout(r, 5000));
data = await fetch(`${MV_BASE}/focus-groups/${fg.id}`, { headers: MV_H }).then(r => r.json());
if (data.status === "completed") break;
}
for (const resp of data.responses || []) {
const name = personaIds.find(p => p.id === resp.persona_id)?.name || "?";
console.log(`[${name}] Q: ${(resp.question||"").slice(0,80)}`);
console.log(` A: ${(resp.answer||"").slice(0,300)}\n`);
}
Example Output
[Frustrated Notion Newcomer] Q: First impression of Notion?
A: Overwhelming. Came from Apple Notes, got a blank page and a YouTube
tutorial rabbit hole. Three hours later, still no functioning to-do list.
[Comparison Shopper] Q: If you switched, what to and why?
A: Obsidian for local-first. Coda for spreadsheet logic. Template ecosystem
keeps me in Notion, but offline is a dealbreaker.
REAL REDDIT (top by score):
[/r/Notion] (847) "I love Notion but the mobile app makes me want to throw my phone"
Error Handling
Search relevance
Search relevance
Add
restrict_sr=true or use sort=top&t=year for higher-quality posts.NSFW filtering
NSFW filtering
Add
nsfw=false and filter over_18 === true posts.