Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mavera.io/llms.txt

Use this file to discover all available pages before exploring further.

Scenario

Customer-reported bugs contain language revealing pain severity beyond a priority label. This job pulls issues labeled “bug” and “customer-reported”, creates user personas for different customer segments, then runs a Mavera Focus Group asking “How critical is this bug to your workflow?” — producing a severity map driven by synthetic customer voices. Flow: Linear GraphQL (issues with labels “bug” + “customer-reported”) → Mavera POST /personasPOST /focus-groups → Poll for results

Code

import os, requests, time

LN, MV = os.environ["LINEAR_API_KEY"], os.environ["MAVERA_API_KEY"]
LB, MB = "https://api.linear.app/graphql", "https://app.mavera.io/api/v1"
LH = {"Authorization": LN, "Content-Type": "application/json"}
MH = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

query = """query {
  issues(filter: {
    labels: { every: { name: { in: ["bug", "customer-reported"] } } }
    state: { type: { nin: ["completed", "canceled"] } }
  }, first: 40, orderBy: createdAt) {
    nodes { identifier title description priority labels { nodes { name } } team { name } }
  }
}"""

r = requests.post(LB, headers=LH, json={"query": query})
if r.status_code == 429:
    time.sleep(int(r.headers.get("Retry-After", 60)))
    r = requests.post(LB, headers=LH, json={"query": query})
r.raise_for_status()
bugs = r.json()["data"]["issues"]["nodes"]
print(f"Fetched {len(bugs)} customer-reported bugs")

bug_block = "\n\n".join(
    f"[{b['identifier']}] {b['title']} (priority: {b.get('priority','none')})\n"
    f"  Team: {(b.get('team') or {}).get('name','Unknown')}\n"
    f"  Description: {(b.get('description') or '')[:400]}"
    for b in bugs)

SEGMENTS = [
    {"name": "Enterprise Admin", "desc": "Manages 200+ person org. Bugs block teams. Values stability and SLAs."},
    {"name": "Startup Founder", "desc": "5-person team. Tolerates quirks, not data loss or broken integrations."},
    {"name": "Product Manager", "desc": "Relies on tool for roadmap planning. Reporting bugs erode stakeholder trust."},
    {"name": "Developer (IC)", "desc": "Lives in tool 8+ hrs/day. API and Git integration matter most."},
]

persona_ids = []
for seg in SEGMENTS:
    time.sleep(0.3)
    p = requests.post(f"{MB}/personas", headers=MH, json={
        "name": f"Bug Triage: {seg['name']}", "description": seg["desc"]}).json()
    persona_ids.append(p["id"])

fg = requests.post(f"{MB}/focus-groups", headers=MH, json={
    "name": "Customer Bug Severity Assessment", "persona_ids": persona_ids,
    "questions": [
        f"Here are {len(bugs)} open bugs:\n\n{bug_block[:3000]}\n\nRate top 5 most critical for YOUR workflow (1-10). Explain.",
        "Which bugs would make you consider switching to a competitor if unfixed for 30 days?",
        "Any bugs that seem minor but compound into major frustration over time?",
    ], "responses_per_persona": 2,
}).json()

for _ in range(30):
    time.sleep(5)
    data = requests.get(f"{MB}/focus-groups/{fg['id']}", headers=MH).json()
    if data.get("status") == "completed":
        break

for resp in data.get("responses", []):
    idx = persona_ids.index(resp["persona_id"]) if resp.get("persona_id") in persona_ids else -1
    name = SEGMENTS[idx]["name"] if 0 <= idx < len(SEGMENTS) else "Unknown"
    print(f"\n[{name}] Q: {resp.get('question','')[:80]}\n  A: {resp.get('answer','')[:400]}")

Example Output

Fetched 17 customer-reported bugs

[Enterprise Admin] Q: Rate top 5 most critical for YOUR workflow (1-10)
  A: 1. ENG-289 "SSO login fails silently after token refresh" — 10/10.
     Locks out entire teams. 40 people unable to access for 2 hours.
  2. ENG-301 "Webhook deliveries drop during deploys" — 9/10.
     Our automation pipeline depends on webhooks.

[Startup Founder] Q: Which bugs would make you switch if unfixed 30 days?
  A: ENG-289 (SSO) is a dealbreaker — we just rolled out SSO and I
     can't tell my team "use password login as a workaround." Also
     ENG-308 (GitHub PR links not syncing) — the Git integration is
     the whole reason we chose Linear.

[Developer (IC)] Q: Any bugs that seem minor but compound?
  A: ENG-322 "Keyboard shortcut 'X' occasionally triggers on wrong
     issue" — I triage 50+ issues daily. One wrong archive per day
     × 5 days = 5 lost issues/week.

Error Handling

The every filter requires ALL listed labels. If your workspace uses “Bug” vs “bug” or “customer_reported”, adjust values. Query issueLabels to discover exact names.
Complex groups with 4 personas may take 60-90s. The loop allows 150s. Check the Mavera dashboard if status never reaches “completed”.
Linear priorities are integers: 0 (none), 1 (urgent), 2 (high), 3 (medium), 4 (low). Map them to text in your prompt if personas need clearer severity context.