npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dopple-ai

v0.1.0

Published

Synthetic user research engine. Generate psychometrically grounded personas from your product data, query them, validate them.

Downloads

26

Readme

dopple

Understand your users before you build. Dopple connects to your product data, creates psychometrically grounded synthetic users, and tells you what to build next — all from the terminal.

Every prediction gets smarter. Dopple tracks what it predicted, what actually happened, and uses that history to improve the next prediction. The more you use it, the more accurate it gets.

dopple insights --product "my SaaS" --posthog-key phx_... --pretty

# 5 Insights:
#
# 1. Power users export heavily but you have no export customization
#    Confidence: ████████░░ 80%  Impact: █████████░ 90%
#    → Add CSV column selection and scheduled exports
#
# 2. 28% of users churn within 7 days — they never finish onboarding
#    Confidence: ███████░░░ 70%  Impact: ████████░░ 80%
#    → Simplify onboarding step 3 or add a guided walkthrough

Use Cases

"What should I build next?" Connect PostHog → Dopple discovers your user segments → generates targeted questions from your data → cross-references persona responses with real behavior → surfaces insights you didn't know.

"Will users pay for this?" Generate a panel of synthetic users grounded in your Stripe + PostHog data. Ask them about pricing, features, positioning. Every answer cites specific data.

"How will users react to this change?" Run a focus group. Inject a stimulus mid-discussion ("competitor just launched a free tier"). Watch personas debate, change their minds, disagree. Get a summary of themes, agreements, and opinion shifts.

"Does our design work?" Have personas review your Figma designs, landing pages, email copy, or pricing pages. Each persona reacts from their specific context — their usage patterns, their frustrations, their personality.

"Does our product match our positioning?" Calibrate personas against your policy docs, brand guidelines, or real survey results. Structured calibration with real math (MAE, Pearson correlation), not LLM vibes.

"Who are my users, really?" Build a knowledge graph from your data. Ask it natural language questions. "Why are users churning?" — get answers grounded in real behavioral patterns.

Install

bun add dopple-ai
# or
npm install dopple-ai

Quick Start

Get insights (the main command)

dopple insights --product "my SaaS" --csv users.csv --pretty
dopple insights --product "my SaaS" --posthog-key phx_... --graph --pretty
dopple insights --product "my SaaS" --posthog-key phx_... --agent  # JSON for AI agents

Predictions are automatically traced. When real outcomes arrive, record them — next predictions improve:

# Record what actually happened
dopple record-outcome \
  --product "my SaaS" \
  --trace-id abc123 \
  --actual "22% churned (predicted 28%)" \
  --mae 0.06 --direction-correct

# View prediction history and accuracy
dopple traces --product "my SaaS" --pretty

As a library

import { Dopple } from "dopple-ai";

const dopple = new Dopple({
  model: "anthropic/claude-sonnet-4-20250514",
  adapters: [{ type: "posthog", apiKey: "phx_..." }],
});

// Get actionable insights — automatically calibrated from past predictions
const report = await dopple.runInsights({ product: "my SaaS app" });
console.log(report.insights);

// Generate personas from data, documents, or both
const personas = await dopple.generate({
  product: "budget tracking app for freelancers",
  count: 5,
  save: "budget-panel",
});

// Every response includes citations and reasoning
const response = await personas[0].ask("Would you pay $15/mo for this?");
console.log(response.response);   // "Honestly, $15 feels steep..."
console.log(response.reasoning);  // "High price sensitivity (neuroticism=0.72)"
console.log(response.citations);  // [{ source: "trait-model", detail: "...", weight: 0.8 }]

// Record real outcomes to improve future predictions
await dopple.recordOutcome(
  "my SaaS app", traceId, "22% churned", "stripe",
  { mae: 0.06, directionCorrect: true, notes: "Over-estimated by 6pp" }
);

Persona generation (three modes)

// From data — clusters real users into segments
const personas = await dopple.generate({
  product: "my SaaS",  // + PostHog/Stripe adapters connected
});

// From documents — extracts stakeholder types
const personas = await dopple.generate({
  product: "Singapore flood risk policy",  // + PDF adapter: --doc policy.pdf
});

// Combined — segments from data, enriched with document knowledge
const personas = await dopple.generate({
  product: "my SaaS",  // + PostHog + --doc product-roadmap.pdf
});

Each persona gets a rich narrative backstory, pain points, goals, and relationship to the product — not bullet-point demographics.

Focus groups

const group = dopple.createFocusGroup("pricing", {
  topic: "Should we raise prices from $10 to $15/mo?",
  product: "project management SaaS",
});

group.addPersonas(personas);
group.setPersonaContext("Sarah", ["You cancelled your subscription last month"]);
group.setPersonaContext("Mike", ["You upgraded to pro 2 weeks ago"]);

const round1 = await group.discuss(llm);
group.inject("A competitor just launched a free tier");
const round2 = await group.discuss(llm);

const summary = await group.summarize(llm);
// { themes, agreements, disagreements, insights, opinionShifts }

Design and messaging review

import { reviewContent } from "dopple-ai";

// Personas review with full context — their usage, frustrations, personality
const review = await reviewContent(llm, personas, {
  type: "pricing_page",
  content: "https://myapp.com/pricing",
  description: "New pricing page with Pro tier at $15/mo",
  questions: ["Is the pricing clear?", "Would you upgrade?"],
});

console.log(review.consensus.wouldActRate);  // 0.4 — only 40% would upgrade
console.log(review.consensus.weaknesses);    // ["Pro tier value not clear"]

// Figma design review
import { reviewFigmaDesign } from "dopple-ai";

const review = await reviewFigmaDesign(llm, personas, {
  accessToken: "fig_...",
  fileKey: "abc123",
  nodeId: "42:0",
});

Surveys

const survey = dopple.createSurvey("pricing-research")
  .freeText("pain", "What's the hardest part about managing expenses?")
  .multipleChoice("switch", "Would you switch to a cheaper alternative?", [
    "Yes, immediately", "Maybe, if same features", "No, I'm loyal",
  ])
  .likert5("satisfaction", "How satisfied are you with your current tool?")
  .numerical("budget", "Max monthly price?", 0, 100);

const results = await dopple.runSurvey(survey, personas);

Calibration

// Qualitative — against policy docs, brand guidelines
const report = await dopple.calibrate(personas, [
  { type: "policy", name: "Return Policy", content: policyText },
]);

// Structured — real math against real survey data
const report = dopple.calibrateStructured(realSurveyData, syntheticResults);
console.log(report.overallMAE);     // 0.073 (7.3pp average error)
console.log(report.correlation);     // 0.847

Knowledge graph

const graph = await dopple.buildGraph();
const answer = await graph.ask(llm, "Why are users churning?");
// { answer: "...", evidence: [...], confidence: 0.82 }

CLI

18 commands. JSON output by default (for AI agents). --pretty for humans. --agent for strict envelope format.

# Insights (the main command — predictions auto-traced)
dopple insights --product "my SaaS" --posthog-key phx_... --pretty

# Personas (from data, documents, or both)
dopple generate --product "budget app" --count 5 --save my-panel --pretty
dopple generate --product "flood risk" --doc policy.pdf --pretty
dopple generate --product "my SaaS" --posthog-key phx_... --doc roadmap.pdf --pretty
dopple ask "Would you pay for dark mode?" --persona my-panel --pretty

# Research
dopple survey --product "my SaaS" --persona my-panel --pretty
dopple focus-group --topic "pricing" --product "my SaaS" --rounds 3 --pretty
dopple review "https://myapp.com" --type landing_page --persona my-panel --pretty
dopple review "Ship faster with AI" --type messaging --pretty

# Calibration
dopple calibrate --source policy.txt --source-type policy --persona my-panel --pretty
dopple calibrate-data --real survey.json --synthetic results.json --pretty

# Data & graph
dopple discover --posthog-key phx_... --product "my SaaS" --pretty
dopple graph --posthog-key phx_... --pretty
dopple query "Why are users churning?" --csv users.csv --pretty

# Prediction tracking (the compounding loop)
dopple traces --product "my SaaS" --pretty
dopple record-outcome --product "my SaaS" --trace-id abc123 --actual "22% churned"

# Management
dopple validate --persona panel.jsonl --pretty
dopple status --posthog-key phx_... --pretty
dopple panels
dopple providers

How It Works

Prediction trace accumulation

Every prediction Dopple makes is traced per product. When real outcomes arrive, they close the loop:

Week 1:  dopple insights → "28% will churn" (trace saved)
Week 2:  dopple record-outcome → "22% actually churned" (accuracy: 6pp error)
Week 3:  dopple insights → calibration history injected → better prediction
Week 8:  dopple insights → "For this product, Dopple's predictions have
          r=0.84 correlation with real outcomes across 12 verified predictions"

The LLM doesn't change. The world model expands. Each verified prediction makes the next one more accurate.

Persona grounding

Every persona is a mathematical object, not a prompt template. Built on the Big Five personality model (OCEAN) — the most validated framework in personality psychology.

Openness:         0.72  → tries new products early, values innovation
Conscientiousness: 0.45  → moderate planning, some impulse buying
Extraversion:     0.31  → decides independently, researches quietly
Agreeableness:    0.68  → trusts recommendations, loyal, avoids conflict
Neuroticism:      0.55  → somewhat price-sensitive, reads negative reviews

Trait vectors compile into deterministic behavioral rules. Same traits = same behavior, every time.

Three generation modes

| Input | Mode | Confidence | |-------|------|-----------| | PostHog, Stripe, CSV | Data — clusters real users → representative persona per segment | Medium-High | | PDF, Markdown, TXT | Documents — extracts stakeholder types → individual persona per stakeholder | Medium | | Both | Combined — segments from data, enriched with document knowledge | High |

Auto-selected based on what you connect. Each persona gets a rich narrative backstory, pain points, goals, and relationship to the product.

Sourced responses

Every response traces back to data:

{
  "persona": "Sarah",
  "response": "I'd probably cancel at $15.",
  "confidence": "medium",
  "reasoning": "High neuroticism drives price anxiety. Payment data shows 34% churn at current price.",
  "citations": [
    { "source": "trait-model", "detail": "neuroticism 0.72 → price sensitivity", "weight": 0.6 },
    { "source": "payment-data", "detail": "34% churned after last price increase", "weight": 0.9 }
  ]
}

Knowledge graph

Builds an in-memory graph from your data — users, events, features, complaints, payments, and their relationships. Query it with natural language or use it to ground personas in specific data neighborhoods.

Calibration (two modes)

Qualitative — calibrate against policy docs, brand guidelines, benchmarks. LLM evaluates alignment.

Structured — calibrate against real survey data. Pure math: Mean Absolute Error per question, Pearson correlation across distributions. No LLM judgment. Publishable.

Memory

Three layers that persist across sessions:

  • Facts — immutable ground truths from your data. Can't be contradicted.
  • Episodes — what the persona said before. Prevents flip-flopping.
  • Stances — distilled positions ("AGAINST price increases"). Compact, always in prompt.

Data Sources

Adapters (read-only — Dopple never writes to your services)

| Adapter | What it provides | |---------|-----------------| | PostHog | User properties, events, behavioral patterns | | Stripe | Subscriptions, churn, MRR, cancel reasons | | Amplitude | User journeys, event export | | Mixpanel | User profiles, event analytics | | HubSpot | CRM contacts, deals, lifecycle stage | | Intercom | Contacts, conversation history, tags | | CSV / JSON | Any structured data from files | | Documents | PDF, Markdown, TXT, HTML files | | Context | Freeform text, URLs |

Integrations (output channels)

| Integration | What it does | |-------------|-------------| | Figma | Personas review your Figma designs — layout, messaging, usability, trust | | Slack | Post survey results, panel responses, insights to Slack channels | | Review | Personas review any content — landing pages, emails, ads, pricing pages |

Roadmap

| Layer | Adapter | What it adds | |-------|---------|-------------| | SAY | Formbricks | Survey responses, NPS, in-app feedback | | SAY | Chatwoot | Support conversations, tickets | | DO | Shopify | Orders, products, customer segments | | DO | RudderStack | Unified customer profiles | | HOW | OpenReplay | Session replays, heatmaps, rage clicks | | HOW | rrweb | Raw DOM recordings, scroll patterns |

The four layers of user understanding:

  • SAY — what users tell you (surveys, support, reviews)
  • DO — what users actually did (events, payments, signups)
  • HOW — how users interacted (session replays, hesitation, scroll depth)
  • WHY — why users behave that way (personality, motivation, beliefs) — Dopple

Custom adapters

Write your own in ~20 lines:

import { registerAdapter, type Adapter, type UserRecord } from "dopple-ai";

class MyAdapter implements Adapter {
  readonly type = "my-source";
  async fetch(): Promise<UserRecord[]> {
    return [{ id: "user-1", properties: { plan: "pro" } }];
  }
}

registerAdapter("my-source", (config) => new MyAdapter(config));

LLM Providers

One string to switch models:

new Dopple({ model: "anthropic/claude-sonnet-4-20250514" })  // default
new Dopple({ model: "openai/gpt-4o" })
new Dopple({ model: "ollama/llama3" })                       // local, free
new Dopple({ model: "groq/llama-3.3-70b-versatile" })        // fast
new Dopple({ model: "openrouter/anthropic/claude-sonnet-4-20250514" })

8 providers: Anthropic, OpenAI, Google, Groq, Together, Fireworks, Ollama, OpenRouter.

Agent Integration

Dopple is designed to be called by AI agents. Every command returns structured JSON by default.

# Claude Code / Codex / any agent can run:
dopple insights --product "my SaaS" --csv users.csv --agent

# Returns single-line JSON envelope:
# {"ok":true,"command":"insights","data":{...}}

Self-documenting: dopple --help --agent returns a JSON schema of all commands.

License

MIT