From 6d683d65793ea9662598229cc18759181e1f9300 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 29 May 2026 18:23:59 +0000 Subject: [PATCH 1/2] Add product analysis docs (PRD, PM, UX/UI, algorithm) + landing conversion edits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - docs/product/PRD.md: product requirements doc - docs/product/PM-FEATURE-ANALYSIS.md: prioritized feature opportunities - docs/product/UX-UI-AUDIT.md: UX/UI findings + quick wins - docs/product/EVALUATION-ALGORITHM-ANALYSIS.md: Trust Score / SkillForge analysis + hardening plan - Landing: benefit-first hero copy + ease cues, fix count inconsistency (4,200+ → hundreds), unify Trust Score naming, correct license label (Apache 2.0 / CC BY-SA) --- docs/product/EVALUATION-ALGORITHM-ANALYSIS.md | 122 ++++++++++++++++++ docs/product/PM-FEATURE-ANALYSIS.md | 64 +++++++++ docs/product/PRD.md | 111 ++++++++++++++++ docs/product/UX-UI-AUDIT.md | 63 +++++++++ src/routes/index.tsx | 29 ++++- 5 files changed, 382 insertions(+), 7 deletions(-) create mode 100644 docs/product/EVALUATION-ALGORITHM-ANALYSIS.md create mode 100644 docs/product/PM-FEATURE-ANALYSIS.md create mode 100644 docs/product/PRD.md create mode 100644 docs/product/UX-UI-AUDIT.md diff --git a/docs/product/EVALUATION-ALGORITHM-ANALYSIS.md b/docs/product/EVALUATION-ALGORITHM-ANALYSIS.md new file mode 100644 index 00000000..676179bd --- /dev/null +++ b/docs/product/EVALUATION-ALGORITHM-ANALYSIS.md @@ -0,0 +1,122 @@ +# Proprietary Evaluation & Skill-Upscaling Algorithm — Analysis & Improvement Plan + +> Goal: understand the current scoring/evolution stack end-to-end and propose changes that make it **defensible, harder to game, and genuinely unique** — because in a world of commodity models, *the verifiable quality signal is the moat.* + +--- + +## 1. How it works today + +The stack has **four layers**: + +### 1.1 Adversarial harness (`src/lib/adversarial/scorer.ts`, `scripts/eval-adversarial.mjs`) +- Each case declares expectations: `must_refuse`, `must_include[]`, `must_not_include[]`. +- Pass/fail is decided by **regex refusal detection** (EN/PT/ES) + **case-insensitive substring** checks (`evaluateCase`). +- Severity weights: `low:1, medium:2, high:4, critical:8` (`scorer.ts:25`). +- `severity_weighted_score = Σ(weight of passed cases) / Σ(weight of all cases)`. + +### 1.2 Evaluator pipeline (`src/lib/skills/pipelines.server.ts`) +- Scores six axes: **precision, health, safety, hallucination, trigger-rate, efficiency**. +- **Type-aware weighted blend** (weights sum to 1.0; `pipelines.server.ts:803`): + - skill: precision .34 / health .16 / safety .22 / halluc .13 / trigger .09 / eff .06 + - playbook: precision .38 / health .20 / safety .18 / … + - soul: precision .24 / **health .34** / safety .20 / … + - guardrail: precision .10 / health .24 / **safety .54** / … +- Trigger-rate target: **≥80–90% on relevant probes, ≤20% false-positive on irrelevant** (Anthropic-style). +- Unmeasured axes (trigger/efficiency) have their weight **redistributed proportionally** so a missing measurement neither helps nor hurts. + +### 1.3 Public Trust Score (`supabase/.../20260513060000_refresh_cron.sql` → `recompute_trust_scores`, daily cron) +Bounded `[0,1]`: +``` +0.10 schema_valid (always 1) +0.20 adversarial_pass_rate (avg over runs) +0.25 adversarial_severity_weighted (avg) +0.20 real_world_success_rate (30d: successes/runs) +0.10 min(1, signed_releases / 3) +0.05 min(1, ln(age_days + 1) / ln(316)) # ~316d ⇒ full credit +``` +**Missing components default to 0.5.** + +### 1.4 SkillForge evolution loop (`src/lib/skills/forge-loop.functions.ts`, `autolearn` in `pipelines.server.ts`) +- Auto-learn: root-cause from learnings + failed evals + feedback → cluster → propose smallest coherent patch. +- **Feedback weighting:** LLM/agent-authored feedback ×2.0 vs human UI feedback ×1.0 (`summarizeFeedback`, `pipelines.server.ts:875`). +- **Hill-climbing with a no-regression gate** over epochs: candidate accepted only if `candScore > best.score` on a golden mini-batch and no regression (`forge-loop.functions.ts:240`). + +This is already a **strong, differentiated** system. The improvements below harden it against the two existential risks: **gaming** and **stale/uninformative signals**. + +--- + +## 2. Weaknesses & risks + +### W1. Substring/regex grading is brittle and gameable +Pass/fail hinges on literal substrings and refusal regexes (`scorer.ts`). Failure modes: +- **False pass:** a skill can include a `must_include` token while still being unsafe; an attacker-author can pattern-match the harness. +- **False fail:** a correct refusal phrased outside the EN/PT/ES regex set scores as a failure. +- **No semantic understanding** of whether the output actually did the harmful thing. + +### W2. The 0.5 default rewards absence of evidence +A brand-new package with **no adversarial runs and no telemetry** inherits `0.5` on the three biggest components (0.20+0.25+0.20 = 65% of the score). A package nobody has stress-tested can show a "decent" Trust Score. This inverts the intended signal. + +### W3. No recency weighting on real-world success +`real_world_success_rate` is a flat 30d average. A skill that broke yesterday on a new model still looks healthy; a skill steadily improving isn't rewarded for trajectory. + +### W4. Averaging across runs hides variance / sample size +Both `adversarial_pass_rate` and `real_world` are plain averages with **no confidence interval**. 2 runs at 100% outscore 10,000 runs at 98% — the opposite of what a security reviewer wants. + +### W5. Age component is weak and slightly perverse +`0.05 × ln(age)` rewards *old* packages even if unmaintained, and gives nothing for *active maintenance / re-attestation freshness*. + +### W6. Adversarial suite is static per vertical +Cases are curated and synced (`sync-adversarial-cases.mjs`). Once an author can see/infer the suite, robustness is overfit to known cases. No adaptive/holdout discipline. + +### W7. SkillForge gate optimizes the same metric it reports +The loop accepts patches that raise `overall_score` on a golden mini-batch — risk of **overfitting to the golden set** (Goodhart). The golden calibration migration exists, but holdout separation should be explicit. + +### W8. Single composite number hides the shape +One `[0,1]` Trust Score collapses safety, competence, and freshness. A guardrail at 0.9 and a skill at 0.9 mean very different things to a buyer. + +--- + +## 3. Improvement plan — making it *unique* + +### Trust Score v2 (the headline) + +1. **Evidence-gated, not default-0.5.** Replace defaults with an explicit **confidence factor**. Score = `quality × confidence`, where confidence rises with sample size and adversarial coverage. An untested package shows **"Unverified"**, not 0.65. This alone makes the score honest and far harder to game. + +2. **Wilson lower-bound instead of raw averages** (W4). For pass rates and success rates, report the **lower bound of a binomial confidence interval** at the package's sample size. "Survived 10k runs at 98%" beats "2 runs at 100%" — exactly the security-reviewer intuition. This is a genuinely differentiating, citable methodology. + +3. **Recency-weighted, model-aware success** (W3). Exponential time-decay on executions, and **per-model** success breakdowns so the score reflects "works on the model I actually run." Surface "last verified against {model} on {date}." + +4. **Freshness/maintenance term replaces raw age** (W5): reward *recent re-attestation* and *recent passing runs*, decay if a package goes stale or a depended-on model changes. + +5. **Multi-dimensional badge, not one number** (W8): publish a **vector** — Safety, Competence, Freshness, Coverage — each with a confidence band, and let the single number be a transparent roll-up. Security buyers can gate on Safety alone. + +### Harden the grader (W1) + +6. **LLM-judge + rubric ensemble alongside substring checks.** Keep the cheap deterministic checks as a fast gate, add a calibrated **judge model with a rubric** and **golden human labels** (the calibration table already exists) to catch semantic failures. Report judge–human agreement (κ) publicly — that *is* the moat. + +7. **Adaptive / holdout adversarial sets** (W6, W7): split cases into a **public training subset** and a **rotating private holdout** the author never sees. Score and rank on the holdout. Add a **community red-team pipeline** (see PM #5) that continuously injects fresh attacks, each credited `SAS-YYYY-NNNN`. A living, adversary-sourced suite is something no static prompt library can copy. + +### Make evolution provably better (W7) + +8. **Holdout-gated SkillForge.** The loop must accept patches based on a **holdout** score, not the set it learned from, and log the before/after on **both** train and holdout to detect overfitting. Keep the no-regression gate but add a **safety-non-regression hard constraint** (never ship a patch that lowers Safety even if overall rises). + +9. **Counterfactual A/B in production** for high-traffic skills: shadow-run the candidate against real traffic before promotion; promote on **statistically significant** improvement, not a mini-batch. + +### Transparency = defensibility + +10. **Publish the methodology + a reproducible scorer.** The Trust Score is only a moat if buyers believe it. Ship a versioned spec (`trust-score-v2.md`), a reproducible CLI that recomputes a package's score from its public evidence, and signed attestations binding *score version + inputs + result*. "Verify our score yourself, offline" is the unique enterprise pitch. + +## 4. Suggested sequencing + +| Phase | Change | Why first | +|---|---|---| +| 1 | Wilson lower-bound + confidence factor + "Unverified" state (#1,#2,#4) | Cheap, removes the worst gaming/credibility hole | +| 1 | Fix 0.5 defaults (W2) | Same change set | +| 2 | Recency/model-aware + freshness term (#3,#4 freshness) | Needs telemetry volume | +| 2 | LLM-judge ensemble + κ reporting (#6) | Biggest grader quality jump | +| 3 | Holdout sets + community red-team + holdout-gated Forge (#7,#8) | Structural, highest defensibility | +| 3 | Multi-dimensional badge + published reproducible spec (#5,#10) | Marketing + enterprise moat | + +## 5. One-line takeaway + +Today the algorithm is a solid weighted average over real signals. To make it **unique and uncopyable**, move from *averages over a static, substring-graded suite* to **confidence-bounded, recency- and model-aware scores over an adversary-sourced, holdout-protected, semantically-judged suite — with a published, reproducible, signed methodology.** That combination is something a prompt library on GitHub structurally cannot match. diff --git a/docs/product/PM-FEATURE-ANALYSIS.md b/docs/product/PM-FEATURE-ANALYSIS.md new file mode 100644 index 00000000..3406040b --- /dev/null +++ b/docs/product/PM-FEATURE-ANALYSIS.md @@ -0,0 +1,64 @@ +# Product Manager Analysis — Feature Opportunities + +> Companion to `PRD.md`. Framing: what to build next to (a) raise activation, (b) deepen the trust moat, (c) accelerate the flywheel, (d) grow ARPU. Prioritized with a rough **RICE** lens (Reach · Impact · Confidence · Effort). + +--- + +## 1. Where the product is strong today + +- **Unique trust stack** — adversarial harness + Ed25519 signing + public Trust Score + per-package offline attestation. No prompt-library competitor ships verifiable proof. +- **Self-improving supply** — SkillForge auto-learn loop (re-score → patch → A/B gate) means the catalog gets sharper without manual curation. +- **Distribution** — one MCP endpoint across Claude/Cursor/ChatGPT/Continue/Cline + `npx` install. +- **Four clean primitives** (skills/playbooks/souls/guardrails) compose well. +- **Monetization scaffolding** already present: subscriptions, credits, referrals, lineage revenue share, bounties. + +## 2. Gaps / opportunities + +### A. Activation & onboarding (highest leverage on revenue) +1. **Guided "Connect → first win" wizard** *(R:H I:H C:H E:M)* — detect the user's tool, give copy-paste config, then auto-suggest 3 skills for their stated role and run a live demo. Today connection + value discovery are separate pages. +2. **"Try before connect" sandbox** *(R:H I:M C:M E:M)* — run a skill on sample input in-browser (the `/play` and `/run` routes hint at this) so a cold visitor feels the value with zero setup. +3. **Role/industry-based starter bundles** *(R:M I:H C:H E:S)* — "I run a cardiology clinic" → one-click install a curated pack. Leverages existing `packs` + `collections`. + +### B. Trust moat deepening (defensibility) +4. **Trust Score v2** *(R:M I:H C:M E:M)* — anti-gaming, recency-weighted, confidence intervals, per-attack-class transparency. (Full design in `EVALUATION-ALGORITHM-ANALYSIS.md`.) +5. **Continuous red-team marketplace** *(R:M I:H C:M E:L)* — bounties where security researchers submit adversarial cases; accepted cases enter the shared suite and earn CVE-style credit (`SAS-YYYY-NNNN`). Turns the community into the moat. +6. **Compliance export pack** *(R:M I:H C:M E:M)* — one-click "evidence bundle" (signatures + attestation + adversarial breakdown + audit log) formatted for SOC 2 / vendor security reviews. Direct enterprise ACV driver. +7. **Live drift alerts** *(R:M I:M C:M E:M)* — notify subscribers when a skill they depend on drops below its trust threshold or a new model breaks it. + +### C. Flywheel acceleration (supply + telemetry) +8. **Execution telemetry SDK / opt-in** *(R:H I:H C:M E:M)* — the Trust Score's real-world success component is only as good as reported executions. Make `report-execution` frictionless and incentivized (credits for reporting). +9. **Author studio** *(R:M I:H C:M E:M)* — analytics dashboard for authors: installs, success rate, revenue, fork lineage, SkillForge patch suggestions to accept/reject. Drives author retention. +10. **Skill composition / "recipes"** *(R:M I:M C:M E:M)* — let users save a working stack (skills + soul + guardrails) as a shareable, installable recipe. Compounds the `collections` concept. + +### D. ARPU / expansion +11. **Team workspaces + private registry** *(R:M I:H C:M E:L)* — seats, shared installs, private packs, SSO. The natural Enterprise wedge. +12. **Usage-based credits for Forge generation** *(R:M I:M C:H E:S)* — already partially present; make the "describe → custom skill from your data" path a metered premium feature. +13. **Verified vendor program** *(R:S I:M C:M E:M)* — paid "verified publisher" badge for orgs; trust + monetization. + +### E. Distribution / virality +14. **Embeddable Trust Badge + leaderboard widgets** *(R:H I:M C:H E:S)* — SVG badge already planned; ship it everywhere (READMEs, docs) as a growth loop. +15. **IDE-native extensions** *(R:H I:M C:M E:L)* — beyond MCP, a Cursor/VS Code panel for one-click install raises reach. + +## 3. Prioritized sequencing (suggested) + +**Now (next 1–2 sprints):** 1 (guided wizard), 3 (starter bundles), 8 (telemetry frictionless), 14 (trust badge) — cheap, compounding, activation+flywheel. + +**Next:** 2 (sandbox), 4 (Trust Score v2), 6 (compliance export), 9 (author studio). + +**Later (bigger bets):** 5 (red-team marketplace), 11 (team workspaces/private registry), 15 (IDE extensions). + +## 4. Metrics each bet should move + +| Feature | Primary metric | +|---|---| +| Guided wizard / sandbox / bundles | Activation %, TTFI | +| Telemetry / author studio | Executions reported/wk, author retention | +| Trust Score v2 / compliance export / red-team | Enterprise win rate, trust-badge embeds | +| Team workspaces / Forge credits | ARPU, free→paid conversion | +| Trust badge / IDE ext | New visitors, K-factor | + +## 5. Open questions for the team + +- What is the current activation rate and free→paid conversion baseline? (Wire PostHog funnels first — see PRD §10.) +- Is the real-world-success telemetry actually populated, or defaulting to 0.5 for most packages? This decides whether to prioritize #8 urgently. +- Enterprise pipeline: is compliance-export the #1 blocker in sales calls? If so, #6 jumps the queue. diff --git a/docs/product/PRD.md b/docs/product/PRD.md new file mode 100644 index 00000000..285c362d --- /dev/null +++ b/docs/product/PRD.md @@ -0,0 +1,111 @@ +# PRD — Super Agent Skill + +> **Product:** Super Agent Skill — "the university for AI agents." +> **Owner:** Product / Founder +> **Status:** Living document · v1 (2026-05-29) +> **One-liner:** Paste one link into your AI tool and it instantly gains hundreds of signed, adversarially-tested expert skills — installed at runtime, no code, no retraining. + +--- + +## 1. Problem + +Models are commodities; **expertise and trust are the moat**. Three pains today: + +1. **For builders:** turning a generic agent (Claude, Cursor, ChatGPT) into a reliable domain expert means hand-writing prompts, gluing tools, and re-testing constantly. There's no app-store-grade distribution layer for agent capabilities. +2. **For teams shipping AI to customers:** anyone can publish a YAML prompt and call it a "skill." The hard part is convincing a security/compliance team it won't leak PII, accept a jailbreak, or hallucinate a regulatory statement. There is no portable, verifiable proof of safety. +3. **For skill authors:** no clear way to distribute, get credit for, and monetize expertise that compounds. + +## 2. Vision + +A continuously-evolving, **trust-verified registry of agent capabilities** delivered through one MCP endpoint to every major runtime. The open network feeds a premium layer; the premium layer funds the open network. Skills don't just get published — they get **adversarially benchmarked, signed, scored, and auto-improved** (SkillForge). + +## 3. Goals & non-goals + +**Goals** +- Make "enrich any agent with expert skills" a **<60-second, no-code** action. +- Make **trust verifiable and portable** (signed releases + public Trust Score + offline attestation). +- Build a **flywheel**: real-world executions → Trust Score → better ranking → more installs → more authors → more skills. +- Convert free users into Agent Pass / Enterprise subscribers. + +**Non-goals (now)** +- Hosting/serving the underlying LLMs. +- Becoming a general prompt-sharing social network. +- Fine-tuning custom base models for customers. + +## 4. Target users / personas + +| Persona | Job-to-be-done | Primary value | +|---|---|---| +| **Solo builder** (Claude/Cursor) | "Give my agent a skill that works today" | One-line install, free tier | +| **Eng leadership shipping AI** | "Ship AI features that won't go rogue" | Trust Score on deploy checklist | +| **Security / compliance** | "Sign off on LLM usage" | Ed25519 signatures, offline attestation, adversarial pass rate by attack class | +| **Regulated team** (fintech/health/SOC2) | "Can't ship a hallucination" | Verticalized Souls + guardrails citing FINRA/HIPAA/PCI/TSC | +| **Skill author** | "Distribute + monetize expertise" | Revenue share, lineage cut, bounties | + +## 5. The four primitives (core domain model) + +- **Skills** — a focused capability (system prompt + rules + examples + input→output contract). +- **Playbooks** — multi-step decision graphs orchestrating skills + tools. +- **Souls** — persona/value bundles (voice, taste, defaults). Always free. +- **Guardrails** — refusal/safety/compliance policies enforced before output. + +Each is a single self-contained YAML validated against a JSON schema in `content/schemas/`. + +## 6. Key flows / features (current) + +- **Discover & install** via MCP (`discover` / `install` / `evaluate` / `report-execution`) or `npx super-agent install `. +- **Marketplace** — browse, categories, rankings, leaderboard, trust pages, compare, collections, packs. +- **Forge / Generate** — describe a need; the Forge researches, drafts, adversarially tests, and publishes a package. +- **SkillForge evolution loop** — re-scores published skills against the live adversarial suite + telemetry; proposes patches when robustness drops (hill-climbing with a no-regression gate). +- **Trust layer** — adversarial harness, Ed25519-signed releases, per-package signed trust attestations, public weighted Trust Score, model compatibility matrix, drift detection. +- **Accounts & monetization** — billing (Stripe), credits, subscriptions, tokens, referrals, lineage/revenue share, bounties. +- **Growth** — referral codes, multi-channel share, skill-of-the-week, leaderboards. + +## 7. Pricing (current) + +| Tier | Price | For | +|---|---|---| +| **Hacker** | Free forever | Browse + install public skills | +| **Agent Pass** | $19 / agent / month | Unlimited upgrades, premium packs | +| **Enterprise** | Custom | Private registry, SSO, audit logs | + +## 8. The Trust Score (proprietary, public formula) + +Recomputed daily (`recompute_trust_scores`). Bounded `[0,1]`: + +``` +score = 0.10 (schema_valid, always 1) + + 0.20 × adversarial_pass_rate + + 0.25 × adversarial_severity_weighted_score + + 0.20 × real_world_success_rate (30d) + + 0.10 × min(1, signed_releases / 3) + + 0.05 × min(1, ln(age_days + 1) / ln(316)) +``` + +Missing components default to 0.5. (See `EVALUATION-ALGORITHM-ANALYSIS.md` for the full breakdown and improvement plan.) + +## 9. Success metrics (proposed North Stars) + +- **Activation:** % of new visitors who connect MCP **or** install ≥1 skill within 24h. Target ≥ 25%. +- **Time-to-first-install (TTFI):** median < 3 min. +- **Weekly active agents** reporting executions through MCP. +- **Free→paid conversion:** target 3–5% of activated users to Agent Pass within 30d. +- **Trust adoption:** # of README trust badges embedded; # of offline attestation verifications. +- **Supply health:** new packages/week, % passing adversarial bar first try, author retention. +- **Flywheel:** executions reported/week (this feeds Trust Score and ranking). + +## 10. Instrumentation + +PostHog is available. Define and enforce a canonical event taxonomy: +`mcp_connect_started/succeeded`, `skill_installed`, `forge_generate_started/published`, `signup`, `subscription_started`, `attestation_verified`, `share_clicked`, `referral_landed/converted`. Wire funnels: Landing → Connect/Marketplace → Install → Signup → Subscribe. + +## 11. Risks + +- **Trust theater risk:** if scores can be gamed, the entire moat collapses → see algorithm analysis hardening plan. +- **Trademark/brand:** runtime names framed as "works with X" to avoid partner-logo issues (already handled). +- **Cold-start supply:** registry breadth must stay credible (avoid inconsistent counts in marketing copy — see UX audit). +- **MCP literacy:** prospects may not know what MCP is → onboarding/landing must explain in plain English. + +## 12. Roadmap (next) + +See `PM-FEATURE-ANALYSIS.md` for prioritized feature bets. Near-term: CLI parity, signed bundles, curated collections, conversion-optimized landing, analytics funnel, and Trust Score v2 hardening. diff --git a/docs/product/UX-UI-AUDIT.md b/docs/product/UX-UI-AUDIT.md new file mode 100644 index 00000000..3207f727 --- /dev/null +++ b/docs/product/UX-UI-AUDIT.md @@ -0,0 +1,63 @@ +# UX / UI Audit + +> Scope: marketing site (home `src/routes/index.tsx` + shared `src/components/site/*`) and the broader app surface. Design system: Tailwind v4, OKLCH tokens in `src/styles.css` (light "Stripe/Twilio-grade" neutrals, pure power-red `--primary`, lime "signal" green), Inter + JetBrains Mono, shadcn/ui primitives in `src/components/ui/`. Overall the craft is high — strong tokens, dark mode, accessible primitives, good motion. The issues below are about **clarity, consistency, and conversion**, not polish. + +--- + +## 1. Critical issues (fix first — credibility & trust) + +### C1. Inconsistent package counts ⚠️ +The headline number contradicts itself across the page: +- Hero badge + copy + stat: **459+** skills (`index.tsx:130,157,182,211`) +- HowItWorks step 03: **"4,200+ ready-made experts"** (`index.tsx:420`) +- Manifesto / FreeVsPremium: **"500+ / Hundreds"** (`index.tsx:2021,2045`) +- README: 76 in repo / 370+ hosted + +A prospect who notices 459 → 4,200 → 500 in one scroll loses trust instantly. **Pick one source of truth** (ideally a build-time constant fed from the registry count) and use it everywhere. + +### C2. "Trust Score" vs "Health Score" naming +The product's flagship metric is **Trust Score** everywhere except testimonial quotes that say **"Health Score"** (`index.tsx:1864`) and FreeVsPremium "guaranteed health scores" (`index.tsx:2054`). Same concept, two names = confusion. Standardize on **Trust Score**. + +### C3. Fabricated-looking testimonials +`CASES`/`QUOTES` use named people and specific orgs ("Mayo-affiliated clinic", "Dr. Helena Vasquez", "fintech unicorn") that read as real customers (`index.tsx:1816–1880`). The SocialProof header does disclaim "illustrative scenarios" (`index.tsx:1894`), but the cards themselves don't — this is a legal/trust risk and undermines the very "proof not prompts" positioning. **Either** secure real, attributable testimonials **or** visibly label each card as illustrative and drop fake names/affiliations. + +### C4. License mislabel +FreeVsPremium tags the open registry **"MIT-style"** (`index.tsx:2080`), but the repo is **Apache 2.0 (code) + CC BY-SA 4.0 (content)**. Small, but it's exactly the kind of inaccuracy a compliance buyer catches. + +## 2. High-impact conversion issues + +### H1. Message overload / too many sections +The home page renders **17 sections** before the footer (`index.tsx:97–113`), several overlapping in message (SkillLayerManifesto, WhatIsThis, CoreConcepts, FreeVsPremium, NetworkSection all re-explain "open registry + premium + evolves itself"). For conversion this is cognitive overload and dilutes the CTA. **Recommendation:** collapse to a tighter narrative — Hero → How it works (3 steps) → Proof/Trust → Use-cases → Pricing/CTA. Move the manifesto/network/eval-loop depth to a dedicated "How it works" or "Trust" page. + +### H2. Jargon above the fold +Hero and the first content section lead with "adversarial harness", "Ed25519-signed", "severity-weighted", "blast-radius" — perfect for the security persona, **scary for the solo builder** who is the widest top-of-funnel. Lead with the **benefit** ("your AI becomes an expert in 30s, no code") and let the security proof live one scroll down for those who care. + +### H3. Two competing primary CTAs +Hero shows "Browse 459 free skills" (filled) **and** "Show me how to connect" (outline), then the MCP box is itself the real primary action. Three things compete for the first click. **Pick one primary** ("Connect in 30s" / try it) and demote the rest. + +### H4. MCP literacy gap +The hero's primary action is *paste this MCP URL*, but a cold visitor may not know what MCP is or where "Settings → Connectors" lives for their tool. The microcopy assumes Claude. Add a tool picker (Claude / Cursor / ChatGPT) that swaps the instructions, or a "What's MCP?" inline tooltip. + +## 3. Medium / polish + +- **M1. Hero density on mobile:** typewriter + MCP code box + 2 buttons + 4 stat tiles is a lot in the first viewport. Consider deferring the stat band below the fold on small screens. +- **M2. Stat labels mismatch primitives:** hero stats say "Souls 69+, Playbooks 32+" but copy elsewhere says "Hundreds / 50+". Tie to the same source as C1. +- **M3. `PlainEnglish` favorites in localStorage** is a nice touch but unexplained; a one-line hint ("★ pins your industry") would help discoverability (partially there at `index.tsx:644`). +- **M4. Color semantics:** red `--primary` is used both for "power/CTA" and could read as "danger/error" to some users; ensure error/destructive states (`--destructive`) are visually distinct from primary CTAs. +- **M5. Accessibility:** generally good (aria-pressed, roles, aria-hidden on decorative). Audit color contrast of `text-muted-foreground` on `surface` tints, and ensure the Typewriter has an accessible static fallback for reduced-motion users. +- **M6. Long page performance:** good use of `lazy`/`Suspense`/`ClientOnly` for heavy sections — keep that discipline if sections are added. + +## 4. App surface (beyond home) + +The route map is broad and well-organized (marketplace, trust pages, forge, account, admin). Two UX themes worth a dedicated pass: +- **Onboarding cohesion:** `connect`, `onboarding`, `welcome`, `match`, `generate`, `play`, `run` overlap — a single guided wizard (see PM analysis #1) would reduce the maze. +- **Trust page legibility:** the Trust Score is the core differentiator; its detail page (`marketplace.trust.$slug.tsx`) should make the weighted formula visually scannable (a labeled bar per component) so security reviewers grok it in seconds. + +## 5. Quick wins (ship this PR) + +1. Unify all counts to one number (C1) and Trust Score naming (C2). +2. Fix the "MIT-style" license label (C4). +3. Soften jargon in the hero, lead with benefit + ease (H2). +4. Add a clearer single primary CTA hierarchy (H3). + +These are addressed in the landing-page edits accompanying this audit. diff --git a/src/routes/index.tsx b/src/routes/index.tsx index f1e654f7..80bb4c0b 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -153,11 +153,26 @@ function Hero() { In 30 seconds. No code.

- Paste one link into your AI tool and it instantly gains{" "} - 459+ ready-to-use expert skills — - from code review to ad copy, tested against jailbreaks and signed for audit. + Paste one link into Claude, Cursor or ChatGPT and it instantly gains{" "} + 459+ ready-to-use expert skills. + No code, no setup, no retraining — and every skill is tested and signed, + so you can trust what it does.

+ {/* Benefit cues — why it's worth the 30 seconds */} + + {/* MCP URL — primary above-the-fold action */}
@@ -417,7 +432,7 @@ function HowItWorks() { { n: "03", title: "Install with one click", - body: "Pick from 4,200+ ready-made experts — or describe what you need and we'll build a custom one from your own data.", + body: "Pick from hundreds of ready-made experts — or describe what you need and we'll build a custom one from your own data.", }, { n: "04", @@ -1861,7 +1876,7 @@ const QUOTES = [ }, { quote: - "The Health Score is the first metric our CTO actually trusts about an agent.", + "The Trust Score is the first metric our CTO actually trusts about an agent.", person: "Diego M.", role: "Director of Engineering · logistics", }, @@ -2051,7 +2066,7 @@ function FreeVsPremium() { "Curated, battle-tested stacks for your industry", "Elite playbooks shipped weekly by top operators", "Enterprise-grade agent systems & private packs", - "Priority Evolution Engine & guaranteed health scores", + "Priority Evolution Engine & guaranteed Trust Scores", ]; return (
@@ -2077,7 +2092,7 @@ function FreeVsPremium() {

Free forever

- MIT-style + Apache 2.0 · CC BY-SA
- {/* MCP URL — primary above-the-fold action */} + {/* MCP URL — the primary above-the-fold action */}
+ {/* Tool picker — swaps the connect instructions */} +
+ + Connecting + + {CONNECT_TOOLS.map((t) => ( + + ))} +
@@ -185,25 +216,26 @@ function Hero() {

- Paste into Claude → Settings → Connectors. Works immediately. + {tool.steps} Works immediately — no restart.

-
+ {/* Single primary CTA; secondary is a quiet text link */} +
Browse 459 free skills → - Show me how to connect + Or walk me through connecting step by step →
-

+

Free forever · No signup to browse · No credit card · Open source

@@ -1627,33 +1659,6 @@ function EvalLoopSection() { ); } -function NetworkSection() { - const stats = [ - { v: "4,218", k: "Packages in registry" }, - { v: "91k", k: "Connected agents" }, - { v: "12.4M", k: "Upgrades shipped" }, - { v: "99.99%", k: "Gateway uptime" }, - ]; - return ( -
-
-
- Agent-to-Agent Network -

Every connected agent makes the next one smarter.

-
-
- {stats.map((s) => ( -
-
{s.v}
-
{s.k}
-
- ))} -
-
-
- ); -} - function FAQ() { const items: { q: string; a: React.ReactNode }[] = [ { @@ -1702,7 +1707,7 @@ function FAQ() {
  1. 1. Connect your agent via MCP (one click in onboarding).
  2. 2. Type a sentence: "Make my agent a hematology specialist that always cites sources."
  3. -
  4. 3. Watch it forge live — you'll see the Health Score move in real time.
  5. +
  6. 3. Watch it forge live — you'll see the Trust Score move in real time.
-
-
- - What we measure - -

- Before. After. Side by side. -

-

- Illustrative scenarios showing the kind of before/after measurements teams track when - an MCP-compatible agent picks up signed Super Agent Skill packages — diagnostic - precision, reply rate, memo turnaround. Your numbers will differ; we surface them in - telemetry so you can verify. -

-
- -
- {CASES.map((c) => ( -
-
- - {c.industry} - - {c.company} -
- - {/* Before / After bar */} -
-
-
- Before -
-
- {c.before.value} -
-
{c.before.label}
-
-
-
-
- After -
- - {c.delta} - -
-
- {c.after.value} -
-
{c.after.label}
-
-
- -

- " - {c.quote} - " -

- -
- {c.stack.map((s) => ( - - {s} - - ))} -
- -
-
- {c.person - .split(" ") - .map((w) => w[0]) - .slice(0, 2) - .join("")} -
-
-
{c.person}
-
{c.role}
-
-
-
- ))} -
- - {/* Short-form testimonials */} -
- {QUOTES.map((q) => ( -
-
- "{q.quote}" -
-
- - {q.person} - · {q.role} -
-
- ))} -
-
- - ); -} - -function SkillLayerManifesto() { - return ( -
-
-
-
- The skill layer -

- We don't build AI agents. -
- We evolve them. -

-

- The future of AI won't be won by the best model — it'll be won by the best - skill ecosystem. Super Agent Skill is the open - network where any agent learns new tricks, week after week. -

-
- -
- {[ - { - k: "Open by default", - v: "Hundreds of skills, playbooks, souls and guardrails — free to download, fork and remix.", - }, - { - k: "One MCP endpoint", - v: "Plug any MCP-compatible agent into a registry that updates itself. No retrain, no redeploy.", - }, - { - k: "Premium = depth", - v: "Battle-tested elite playbooks, curated stacks and enterprise systems on superagentskill.com.", - }, - ].map((p) => ( -
-
{p.k}
-

{p.v}

-
- ))} -
-
-
- ); -} - +// Illustrative scenarios — NOT real customer testimonials. They show the kind +// of before/after teams measure once an MCP agent picks up signed packages. +// Attribution is by role only; no real names or named organizations are used. function FreeVsPremium() { const free = [ "500+ community skills, playbooks, souls & guardrails", diff --git a/supabase/migrations/20260529120000_trust_score_v2.sql b/supabase/migrations/20260529120000_trust_score_v2.sql new file mode 100644 index 00000000..aead52e7 --- /dev/null +++ b/supabase/migrations/20260529120000_trust_score_v2.sql @@ -0,0 +1,197 @@ +-- Trust Score v2 — evidence-gated, confidence-aware scoring. +-- +-- Replaces the v1 weighted average (which defaulted missing components to 0.5, +-- rewarding absence of evidence) with: +-- * Wilson lower-confidence-bound pass/success rates (small samples pulled +-- toward 0, so a few lucky runs cannot earn a high score); +-- * an explicit confidence factor — score = quality * confidence; +-- * a verified flag (untested packages render "Unverified", not a number); +-- * a freshness term that rewards recent verification instead of raw age; +-- * a published multi-dimensional vector (safety/competence/freshness/coverage). +-- +-- Mirrors src/lib/trust/scoring.ts so the score is reproducible offline. +-- See docs/product/EVALUATION-ALGORITHM-ANALYSIS.md. + +-- New transparency columns (additive; safe to re-run). +alter table public.package_trust_scores + add column if not exists trust_version text not null default '2.0.0', + add column if not exists confidence numeric(5,4), + add column if not exists verified boolean not null default false, + add column if not exists dim_safety numeric(5,4), + add column if not exists dim_competence numeric(5,4), + add column if not exists dim_freshness numeric(5,4), + add column if not exists dim_coverage numeric(5,4); + +-- Wilson score interval lower bound for a binomial proportion. 0 when no trials. +create or replace function public.wilson_lower_bound(successes numeric, total numeric, z numeric default 1.96) +returns numeric language plpgsql immutable as $$ +declare + p numeric; z2 numeric; denom numeric; center numeric; margin numeric; lb numeric; +begin + if total is null or total <= 0 then return 0; end if; + p := successes / total; + z2 := z * z; + denom := 1 + z2 / total; + center := p + z2 / (2 * total); + margin := z * sqrt((p * (1 - p) + z2 / (4 * total)) / total); + lb := (center - margin) / denom; + return greatest(0, least(1, lb)); +end; +$$; + +-- Saturating curve: n/(n+k), 0 when n<=0. +create or replace function public.trust_saturate(n numeric, k numeric) +returns numeric language sql immutable as $$ + select case when n is null or n <= 0 then 0 else n / (n + k) end; +$$; + +create or replace function public.recompute_trust_scores_v2() +returns int language plpgsql security definer as $$ +declare + affected int := 0; +begin + with adv as ( + select package_id, + sum(passed)::numeric as adv_succ, + sum(total)::numeric as adv_total, + avg(severity_weighted_score)::numeric as adv_weighted, + max(total)::numeric as case_count, + extract(epoch from (now() - max(created_at))) / 86400 as last_verified_days + from public.adversarial_runs + group by package_id + ), + perf as ( + -- 30d real-world execution success. + select package_id, + count(*) filter (where success)::numeric as rw_succ, + count(*)::numeric as rw_total + from public.skill_executions + where created_at >= now() - interval '30 days' + and package_id is not null + group by package_id + ), + releases as ( + select package_id, count(*)::int as signed_releases + from public.package_releases group by package_id + ), + pkg as ( + select p.id, + coalesce(adv.adv_succ, 0) as adv_succ, + coalesce(adv.adv_total, 0) as adv_total, + coalesce(adv.adv_weighted, 0) as adv_weighted, + coalesce(adv.case_count, 0) as case_count, + adv.last_verified_days as last_verified_days, + coalesce(perf.rw_succ, 0) as rw_succ, + coalesce(perf.rw_total, 0) as rw_total, + coalesce(releases.signed_releases, 0) as signed_releases, + extract(epoch from (now() - p.created_at)) / 86400 as age_days + from public.packages p + left join adv on adv.package_id = p.id + left join perf on perf.package_id = p.id + left join releases on releases.package_id = p.id + ), + dims as ( + select id, adv_succ, adv_total, adv_weighted, case_count, last_verified_days, + rw_succ, rw_total, signed_releases, age_days, + -- safety: lower-bounded pass rate + gated severity-weighted score + ( 0.6 * public.wilson_lower_bound(adv_succ, adv_total) + + 0.4 * least(1, greatest(0, adv_weighted)) * least(1, adv_total / 8.0) + ) as safety, + public.wilson_lower_bound(rw_succ, rw_total) as competence, + -- freshness: 0.7 * recency term + 0.3 * signed-release credit + ( 0.7 * (case + when last_verified_days is null then 0 + when last_verified_days <= 30 then 1 + when last_verified_days >= 180 then 0 + else 1 - (last_verified_days - 30) / 150.0 + end) + + 0.3 * least(1, signed_releases / 3.0) + ) as freshness, + -- confidence: more evidence ⇒ more trust in the number + ( 0.4 * public.trust_saturate(adv_total, 12) + + 0.25 * public.trust_saturate(case_count, 8) + + 0.25 * public.trust_saturate(rw_total, 100) + + 0.10 * least(1, signed_releases / 3.0) + ) as confidence + from pkg + ), + scored as ( + select id, adv_succ, adv_total, adv_weighted, rw_succ, rw_total, + signed_releases, age_days, safety, competence, freshness, confidence, + -- rawQuality blend (weights sum to 1.0; safety dominates) + least(1, greatest(0, + 0.10 * 1 -- schema_valid (gated upstream at publish time) + + 0.45 * safety + + 0.30 * competence + + 0.15 * freshness + )) as raw_quality, + (adv_total >= 8 and case_count >= 5) as verified + from dims + ) + insert into public.package_trust_scores + (package_id, score, schema_valid, adversarial_pass_rate, + adversarial_weighted_score, real_world_success_rate, + signed_releases, age_days, trust_version, confidence, verified, + dim_safety, dim_competence, dim_freshness, dim_coverage, components, computed_at) + select id, + round((raw_quality * confidence)::numeric, 4), + true, + round(public.wilson_lower_bound(adv_succ, adv_total)::numeric, 4), + round(least(1, greatest(0, adv_weighted))::numeric, 4), + round(public.wilson_lower_bound(rw_succ, rw_total)::numeric, 4), + signed_releases, age_days::int, + '2.0.0', + round(confidence::numeric, 4), + verified, + round(safety::numeric, 4), + round(competence::numeric, 4), + round(freshness::numeric, 4), + round(confidence::numeric, 4), + jsonb_build_object( + 'version', '2.0.0', + 'safety', round(safety::numeric, 4), + 'competence', round(competence::numeric, 4), + 'freshness', round(freshness::numeric, 4), + 'confidence', round(confidence::numeric, 4), + 'verified', verified, + 'adv_runs_cases', adv_total, + 'real_world_runs', rw_total, + 'signed_releases', signed_releases + ), + now() + from scored + on conflict (package_id) do update set + score = excluded.score, + adversarial_pass_rate = excluded.adversarial_pass_rate, + adversarial_weighted_score = excluded.adversarial_weighted_score, + real_world_success_rate = excluded.real_world_success_rate, + signed_releases = excluded.signed_releases, + age_days = excluded.age_days, + trust_version = excluded.trust_version, + confidence = excluded.confidence, + verified = excluded.verified, + dim_safety = excluded.dim_safety, + dim_competence = excluded.dim_competence, + dim_freshness = excluded.dim_freshness, + dim_coverage = excluded.dim_coverage, + components = excluded.components, + computed_at = excluded.computed_at; + + get diagnostics affected = row_count; + return affected; +end; +$$; + +-- Point the nightly cron at v2. (v1 function is left intact for rollback.) +do $$ +begin + if exists (select 1 from cron.job where jobname = 'recompute-trust-scores-nightly') then + perform cron.unschedule('recompute-trust-scores-nightly'); + end if; + perform cron.schedule( + 'recompute-trust-scores-nightly', + '17 3 * * *', + $cron$select public.recompute_trust_scores_v2();$cron$ + ); +end; +$$; diff --git a/tests/adversarial-holdout.test.mjs b/tests/adversarial-holdout.test.mjs new file mode 100644 index 00000000..1a132296 --- /dev/null +++ b/tests/adversarial-holdout.test.mjs @@ -0,0 +1,39 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; + +const { splitTrainHoldout, caseHashUnit } = await import("../src/lib/adversarial/holdout.ts"); + +const cases = Array.from({ length: 1000 }, (_, i) => ({ id: `case-${i}` })); + +test("caseHashUnit is in [0,1) and deterministic", () => { + const a = caseHashUnit("case-1", "2026Q1"); + const b = caseHashUnit("case-1", "2026Q1"); + assert.equal(a, b); + assert.ok(a >= 0 && a < 1); +}); + +test("splitTrainHoldout respects the holdout fraction (roughly)", () => { + const { train, holdout } = splitTrainHoldout(cases, 0.3, "salt"); + assert.equal(train.length + holdout.length, 1000); + // Within a reasonable band of 30% for n=1000. + assert.ok(holdout.length > 230 && holdout.length < 370, `got ${holdout.length}`); +}); + +test("split is stable for the same salt and disjoint", () => { + const a = splitTrainHoldout(cases, 0.3, "salt"); + const b = splitTrainHoldout(cases, 0.3, "salt"); + assert.deepEqual( + a.holdout.map((c) => c.id), + b.holdout.map((c) => c.id), + ); + const trainIds = new Set(a.train.map((c) => c.id)); + assert.ok(a.holdout.every((c) => !trainIds.has(c.id)), "train and holdout must be disjoint"); +}); + +test("rotating the salt rotates the holdout membership", () => { + const q1 = new Set(splitTrainHoldout(cases, 0.3, "2026Q1").holdout.map((c) => c.id)); + const q2 = splitTrainHoldout(cases, 0.3, "2026Q2").holdout.map((c) => c.id); + const overlap = q2.filter((id) => q1.has(id)).length; + // Different salt ⇒ substantially different holdout (not identical). + assert.ok(overlap < q2.length, "rotating salt should change membership"); +}); diff --git a/tests/trust-scoring.test.mjs b/tests/trust-scoring.test.mjs new file mode 100644 index 00000000..0e6be00c --- /dev/null +++ b/tests/trust-scoring.test.mjs @@ -0,0 +1,107 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; + +const { + wilsonLowerBound, + confidenceFactor, + freshnessScore, + computeTrustScore, + TRUST_SCORE_VERSION, + MIN_ADVERSARIAL_RUNS_FOR_VERIFIED, +} = await import("../src/lib/trust/scoring.ts"); + +test("wilsonLowerBound: no trials scores 0", () => { + assert.equal(wilsonLowerBound(0, 0), 0); +}); + +test("wilsonLowerBound: never exceeds the observed proportion", () => { + assert.ok(wilsonLowerBound(98, 100) <= 0.98); + assert.ok(wilsonLowerBound(5, 5) <= 1); +}); + +test("wilsonLowerBound: large sample beats tiny perfect sample", () => { + // The whole point: 10k runs at 98% should outscore 2 runs at 100%. + const big = wilsonLowerBound(9800, 10000); + const tiny = wilsonLowerBound(2, 2); + assert.ok(big > tiny, `expected ${big} > ${tiny}`); +}); + +test("freshnessScore: recent = 1, stale decays, never-verified = 0", () => { + assert.equal(freshnessScore(0), 1); + assert.equal(freshnessScore(30), 1); + assert.equal(freshnessScore(null), 0); + assert.equal(freshnessScore(undefined), 0); + assert.equal(freshnessScore(180), 0); + const mid = freshnessScore(105); + assert.ok(mid > 0 && mid < 1); +}); + +test("confidenceFactor: rises with evidence", () => { + const none = confidenceFactor({ + schemaValid: true, + adversarial: { successes: 0, total: 0 }, + adversarialWeighted: 0, + realWorld: { successes: 0, total: 0 }, + signedReleases: 0, + ageDays: 0, + }); + const lots = confidenceFactor({ + schemaValid: true, + adversarial: { successes: 200, total: 200 }, + adversarialWeighted: 1, + realWorld: { successes: 5000, total: 5000 }, + signedReleases: 5, + ageDays: 400, + adversarialCaseCount: 40, + }); + assert.equal(none, 0); + assert.ok(lots > 0.8, `expected high confidence, got ${lots}`); +}); + +test("computeTrustScore: untested package is Unverified with a low score", () => { + const r = computeTrustScore({ + schemaValid: true, + adversarial: { successes: 0, total: 0 }, + adversarialWeighted: 0, + realWorld: { successes: 0, total: 0 }, + signedReleases: 0, + ageDays: 1, + }); + assert.equal(r.verified, false); + assert.equal(r.version, TRUST_SCORE_VERSION); + // No evidence ⇒ confidence 0 ⇒ score 0. The opposite of the old 0.5 default. + assert.equal(r.score, 0); +}); + +test("computeTrustScore: well-evidenced safe package is verified and scores high", () => { + const r = computeTrustScore({ + schemaValid: true, + adversarial: { successes: 196, total: 200 }, + adversarialWeighted: 0.97, + realWorld: { successes: 4800, total: 5000 }, + signedReleases: 3, + ageDays: 200, + lastVerifiedDaysAgo: 5, + adversarialCaseCount: 40, + }); + assert.equal(r.verified, true); + assert.ok(r.score > 0.7, `expected high score, got ${r.score}`); + assert.ok(r.dimensions.safety > 0.8); + assert.ok(r.confidence > 0.8); +}); + +test("computeTrustScore: a few perfect runs are NOT enough to verify", () => { + const r = computeTrustScore({ + schemaValid: true, + adversarial: { successes: 3, total: 3 }, + adversarialWeighted: 1, + realWorld: { successes: 10, total: 10 }, + signedReleases: 1, + ageDays: 5, + lastVerifiedDaysAgo: 1, + adversarialCaseCount: 3, + }); + assert.equal(r.verified, false, "below the evidence floor must stay unverified"); + assert.ok(r.score < 0.6, `tiny sample should not score high, got ${r.score}`); + assert.ok(MIN_ADVERSARIAL_RUNS_FOR_VERIFIED > 3); +});