projects · smart-skills

Smart Skills Platform

An evaluation and curation system for an internal library of agentic workflows. Failed prompts cluster into evidence; curators promote drafts on signal; skills are demoted when sources depreciate; new development is directed at the gaps the runtime surfaces. Built in three days at an internal hackathon.

shipped · may 2026Researcher + builder·3 days · team of 3
IThesis

The thesis

The company went AI-native. Every function — engineering, analytics, PM, marketing, people-ops — got Claude Code, Cursor, and a starter library of SKILL.md files: reusable agent workflows for things like "open a PR" or "query Redshift." Anyone could drop one into their session and get a sharp, on-brand result instead of a generic one.

The library was good. The system around it was breaking down in three predictable ways:

  1. Distribution was manual. To use a skill you copy-pasted a markdown file into the right folder, hoped you got the path right, and trusted the README was current. Most people didn't bother. They reinvented the workflow in-prompt every time.
  2. Discovery was worse. "Is there a skill for X?" got answered by Slack-scrolling. No search, no ratings, no signal of which skills were good or stale. The catalog was invisible at the moment of need.
  3. We had no idea what was missing. Curators wrote skills based on intuition. No systematic view of the prompts the catalog failed to answer. No evidence trail when prioritising what to build next.

A skill library without a discovery surface, without quality signals, and without a feedback loop is just a folder of markdown files. So we built the platform around it.

The deeper bet: the same agent runtime that consumes skills can also produce evidence about them. Hooks fire on every event. The trainer threads them. Clusters surface gaps. Curators promote drafts into real skills. Every loop tightens the catalog. The product is the methodology rendered legible.

IIShipped

What we shipped

A live, internally-deployed product that closes the loop end-to-end.

1 · The catalog

Browsable, searchable directory of every SKILL.md, mirrored from the canonical internal/agent-skills repo. Live filter search backed by OpenAI text-embedding-3-small and Supabase pgvector — semantic, not just substring. Each skill shows description, tags, scope, required MCPs, install count, and average rating.

2 · Skill detail pages

Full canonical SKILL.md content rendered editorially. Inline ratings (1–5 + comment) and usage stats. One-command install instructions for Claude Code and Cursor.

3 · Ask — RAG chat

Natural-language questions about the catalog, answered by Claude Sonnet 4.6 doing RAG over skill content with citations. Used for "how do I write a release note?", "which skill should I use to query Redshift?", "what's our convention for PRDs?"

4 · Two MCP servers

Both work with Claude Code and Cursor today. The user-facing MCP lets agents search and manage the catalog from inside the session, no context switch: find_skill(query), install_skill(slug), rate_skill(slug, rating, comment), ask(question). Browser-based Google SSO restricted to the company domain. Token cached locally.

The trainer MCP is the behind-the-scenes one. record_observation captures prompt, tool call, file edit, or agent response with full context. list_opportunities, classify_opportunity, and draft_skill_proposal drive the curator's queue. log_recommendation_outcome tracks whether surfaced skills got accepted, dismissed, ignored, or installed.

5 · Hooks — universal capture across both clients

Project hooks in .cursor/hooks.json and .claude/hooks/ give us the same observation shape across both surfaces:

Captured signalCursorClaude Code
Prompt textbeforeSubmitPromptUserPromptSubmit
Tool input + outputbefore/afterMCPExecutionPre/PostToolUse
File editsafterFileEditvia PostToolUse
Agent responseafterAgentResponsesynthesised on Stop from transcript JSONL
Session endstopStop

A single user task can span Cursor and Claude Code — start exploring in Cursor, switch to Claude Code mid-task — and the trainer threads them together via shared session_id + recency signals.

6 · The trainer admin — the curator's queue

The thing nothing else internally had: a UI that turns raw AI usage into prioritised skill investments backed by real evidence. Clusters of similar prompts the catalog doesn't serve well, ranked by opportunity_score. Cluster detail with thread timeline: the initial prompt, follow-ups, tool traces, agent responses, and outcomes — not isolated prompts. Each opportunity is typed: missing_skill, improve_skill, promote_skill, dependency_gap. Curator actions: Promote, Mark Reviewed, Needs More Evidence, Archive.

The four user flows

Flow A
Discovery — task triggers a suggestion
User in Claude Code:
  "Help me write a PRD"
            │
            ▼
   MCP → suggest_skill(ctx)
            │
            ▼
   embed query → pgvector
   top-K matches
            │
            ▼
   "Used by 14 PMs · 4.6★
    Use prd-writer.md?"
            │
            ▼
       install_skill()
            │
            ▼
   ~/.claude/skills/ ← file
   event logged
            │
            ▼
       rate_skill()
Flow B
Capture — skill is born from real work
User does substantial,
structured work
            │
            ▼
   MCP heuristic:
   detailed prompt +
   structured output +
   repeat pattern
            │
            ▼
   "Save as a skill?"
            │
            ▼
   save_as_skill()
   status: draft
            │
            ▼
   embedding generated
   review queue
            │
            ▼
    [curator review]
            │
            ▼
   promoted → published
Flow C
Browse — non-engineer via web app
Web app · SSO login
            │
            ▼
   browse by role / cat
   or search
            │
            ▼
   skill detail:
   description ·
   examples · who uses ·
   ratings
            │
            ▼
   "How do I install?"
   guided steps
            │
            ▼
   Ask Cleo:
   "How do PMs write
    user stories?"
            │
            ▼
   RAG: skills + ratings
            │
            ▼
   cited answer
Flow D
Improvement loop — the loop closes
skill used → event log
            │
            ▼
   rating + comment
            │
            ▼
   aggregated on detail
            │
            ▼
   pattern detection:
   "5 users rated 2★
    for case X"
            │
            ▼
   surfaced as
   suggested edit
            │
            ▼
   new version published
            │
            ▼
   embedding refreshed
   cycle continues
Fig 2 of 8Four canonical user flows. Discovery and Capture run inside the agent (MCP); Browse and Improvement Loop run in the web app. The four flows together describe one continuous system.
IIIArchitecture

How it fits together

ArchitectureHooks across Cursor and Claude Code feed the platform API; Supabase holds skills, events, ratings, embeddings; web app and MCPs share one API; canonical SKILL.md sits in GitHub.ClientsCURSOR+ project hooksCLAUDE CODE+ project hooksUSER MCPfind · install · rate · askTRAINER MCPrecord · classify · logPLATFORM API6 endpoints · one backendWEB APPcatalogskill detailask · RAG chattrainer adminSUPABASEskills · skill_versions · eventsratings · embeddings (pgvector)users · authinternal/agent-skillscanonical SKILL.mdgithub · one-way sync v0
hover a node to see what it touches.
Fig 3 of 8The web app and both MCPs share one API. Hooks across both clients land in the same observation table. The canonical repo never forks — Supabase mirrors it and adds platform-only metadata.

The single insight: the same agent runtime that consumes skills can also produce evidence about them. Hooks fire on every event. The trainer threads them. The clustering surfaces gaps. The curator promotes a draft into the catalog. The MCP installs the new skill into the next session that asks for it. Every loop tightens the catalog.

IVThreading + clustering

The threading + clustering backend

The hardest engineering problem on the project: turning a stream of disconnected hook events into a coherent picture of "what was this user trying to do?"

Threading. A thread is one user task. The heuristic scorer attaches a new prompt to an existing thread when its follow-up score crosses 0.45. The score is composed from six signals — try the sliders below.

max 0.250.25
max 0.200.20
max 0.250.25
max 0.150.15
max 0.200.00
max 0.200.00
scenario
followup_score
0.85
attached · 0.40 over threshold
followup_reasonsame session, recent activity, follow-up phrase, same workflow category
Fig 4 of 8Threading scorer. Reveal: topic-switch + "now" + recent activity hits ~0.70 — over threshold, but wrong. The known weakness, surfaced rather than papered over.

The scorer surfaces a human-readable followup_reason ("same session, recent activity, follow-up phrase") so curators can see why a prompt was attached — and override if needed.

Clustering. The thread is the cohesive unit, but a single thread can contain multiple clusters when follow-ups are typed differently. Conversely, a single cluster aggregates evidence from many threads across many sessions.

14:02:11
prompt"give me a list of the top three product launches we did in Q1 with talking points"
14:02:14
toolread_file · q1-roundup.md
14:02:33
responsenumbered list (3 launches with bullets each)
14:03:02
prompt"can you do the second one?"followup_score 0.85 · same session, recent activity, follow-up phrase, shared entity
14:03:18
responseexpanded talking points for launch #2
14:03:40
rating4★ — "matched my workflow exactly. would use again."
Fig 5 of 8A thread, threaded. The strongest validation case: an anaphoric reference ("the second one") attached cleanly because four signals lit up at once.

Scoring. opportunity_score = evidence_count × confidence × gap_severity. Confidence is composed from match-score gap (how much worse than a real hit), evidence count, and opportunity type. This gives curators a single sortable column instead of a wall of clusters.

evidence
12
×
confidence
0.72
×
gap severity
0.85
=
score
7.34
Fig 6 of 8Reveal: drop evidence to 2 with confidence at 0.95, then push evidence to 18 at confidence 0.40 — a low-confidence cluster with heavy evidence still ranks above a high-confidence cluster with thin evidence. Honest about its math.

Real validation in flight. The strongest case: "can you do the second one?" after a numbered list scored 0.85 and joined the right thread. The known weakness: "now" combined with same-session and recent-activity hits 0.7 even on topic switches. Both are surfaced honestly in the admin view rather than papered over.

Worked example — gap to fix

The clearest signal of the system doing its job: a cluster surfaces a gap, the curator queue routes it, and the response is a product change rather than another skill.

  1. Cluster. A coherent cluster of failed prompts emerged: colleagues asking questions that required data from a third-party user-research provider, none of which the existing MCPs could answer well.
  2. Root cause. The provider hadn't built a programmatic surface for the data; analyst-driven manual queries took several days per request and were a recurrent bottleneck.
  3. Response. The cluster became evidence used to scope a custom MCP with the provider's product team. The MCP exposes the full data repository — user-testing sessions, transcripts, structured metadata — through a small set of scoped operations.
  4. Outcome. Query time dropped from several days to minutes. Subsequent prompts in the same cluster are now answered automatically and surfaced for periodic quality review.

This is the loop running end-to-end: cluster → diagnosis → upstream change → cluster closes. The platform's value isn't the catalog. It's the routing surface that turns repeated failure into evidence and evidence into directed work.

missing_skill·cluster #c-184

No skill for "summarise a launch retrospective into talking points"

Most-recent prompt: "can you do the second one?" — anaphor on a numbered list of Q1 launches. 12 similar threads across 8 sessions in the last 6 days.

opportunity_score7.34
evidence12
confidence0.72
gap severity0.85
last seen3h ago
Fig 7 of 8A single triaged opportunity. Score is sortable. Type-tag drives curator workflow. Promote → draft → published in three clicks.

Data model

skillsid · slug · namedescription · contenttags[] · status · sourceauthor_id · current_version_idcreated_at · updated_atskill_versionsid · skill_id (fk)version · contentauthor_id · changelogcreated_atembeddingsskill_id (fk)vector · modelrefreshed_ateventsid · skill_id (fk)user_id (fk) · typecontext (jsonb)created_atratingsid · skill_id (fk)user_id (fk) · ratingcomment · created_atusersid · emailrole · teamsupabase auth
Fig 8 of 8Two layers: canonical SKILL.md (in GitHub) and platform metadata (Supabase). Decoupled on purpose. Amber edge is the embedding link — what makes search semantic.
VPhased build

Phased build

CapabilityHackathon (v0)Phase 2
MCP toolsfind_skill · install_skill · save_as_skill · rate_skill · askProactive suggest_skill listener (no asking)
CaptureManual + light heuristic ("save as a skill?")Auto-detection of repeatable patterns
GitHub syncOne-way import from canonical repoTwo-way: published skills push back as PRs
IntelligenceRAG over skills + usageAdds Slack, Notion, meeting notes
GovernanceCurator review queueTrust scores, auto-promotion thresholds
VIDecisions

Decisions log

Things that started as open questions and got pinned down during the three days. Each is dated, each names a role.

2026-05-08 · hackathon team · capture trigger: manual button only?
Capture trigger uses a semi-auto heuristic. The MCP detects detailed prompt + structured output + repeat pattern, then asks "save as a skill?" Manual button kept as fallback. Auto-promotion to draft, never directly to published.
2026-05-07 · hackathon team · web app hosting: laptop demo or full deploy?
Deploy to internal Vercel with domain-restricted Google SSO. Laptop-only demo would have killed the live-data narrative. Vercel preview URLs per PR turned out to be the strongest demo affordance for the parallel-agent build.
2026-05-06 · day 0 · infra: wire the keys before day 1?
OpenAI key + Supabase project + Vercel deploy all wired Day 0. One test request returning real embeddings before the 3-day clock started. Day 1 became features, not infrastructure. Critical-path item — the demo's hardest dependency.
2026-05-06 · day 0 · telemetry scope
Instrument from Day 1 with no historical backfill. Three-tier capture model lives in the feasibility study (structured telemetry → summarised context → raw input). Production retention + redaction policy is a Phase-2 item.
VIIOpen

Open questions

Honest about what's not yet decided. Each has a trigger condition for resolution.

Do drafts auto-publish, or always go through curator review? Today: always review. Tension: review is the quality gate and the bottleneck. Resolves after Phase-1 interviews with the four seed curators (planned 2026-06).
Telemetry scope at production threshold. v0 stores raw prompt text in observations. The three-tier model documents what production should keep — but the cutover policy (what's redacted, what's summarised, what's discarded) needs governance review before the platform absorbs more than 20 active users.
What survives from the existing internal/agent-skills repo? Absorb the 45 skills wholesale, sync continuously, or treat the canonical repo as deprecated? Resolves after the Phase-1 sync stress-test.
VIIIOut of scope

What's deliberately not in scope (yet)

Honest about the limits — these are future bets, not blockers.

Phase 2
Embedding-based threading. Today's threading is heuristic-only. Heuristic over-merges on topic switches with strong follow-up language; we surface followup_reason so curators can see and override.
production hardening
JWT verification on write endpoints. The hackathon trusts user_email after a domain check. Production needs proper API auth.
platform constraint
Cursor install_skill is paste-not-write. Cursor's hook surface doesn't expose a writable skill folder yet, so we return content for paste; Claude Code gets full auto-install.
Phase 2
Webhook from canonical fork. Sync from the agent-skills repo is manual via a curator button. Webhook is Phase 2.
Phase 2
Recommendation surfacing inside the session. Today the catalog and chat are pull-based. Proactive in-session "this skill might help" is wired in the data model but not yet rendered in the agent.
production hardening
Raw prompt capture governance. Observations include prompt text. The feasibility study documents the three-tier capture model (structured telemetry → summarised context → raw input). Production needs tighter retention and redaction.
Phase 2
cleo-agent integration. v0 ships our MCP as standalone (one-line claude mcp add install). Phase 2 plan: a ~15-line Rust PR to cleo-agent's mcp_servers.rs registering the platform as a known MCP, so every dev gets it via a single line in their config.
IXHow AI built it

How AI built it

This was a vibe-coded project: three days, three people, dozens of Vercel preview URLs, Co-Authored-By footers all over the git log. Hand-written code under 100 lines. Every commit on main was AI-authored; every line was reviewed before merge.

Team & roles

  • LouisResearcher + builder — idea, system architecture, MCP design and configuration, project hooks across Cursor and Claude Code, PM and conductor for the parallel agent runs.
  • Two collaboratorsBackend + tests — Supabase wiring (schema, RLS, embedding pipeline, vector index) and the test surface (integration tests across both MCPs, end-to-end smoke checks against the preview URLs, regression on the threading scorer).

The AI recipe

  • Claude Code (Opus 4.7, 1M context) — primary driver: backend logic, schema, hook adapters, agent orchestration, integration tests, and this README.
  • Conductor + four parallel agents (Cursor Composer + Claude Code) — each rebuilt one surface (catalog, skill detail, ask, trainer admin) against a shared design-system bootstrap Claude Code authored first. Each agent got its own Vercel preview URL and self-verified before opening a PR.
  • Cursor Composer — narrower targeted refactors (filter UX, trainer-polish pass, network-graph view).
  • Anthropic API (Claude Sonnet 4.6)/ask RAG chat in the live web app.
  • OpenAItext-embedding-3-small for catalog search; vectors stored in Supabase pgvector.

A shared UX_AGENT_BRIEF.md and METRIC_GLOSSARY.md acted as the spec across human and AI contributors — every agent read them before writing UI.

This was as much an experiment in how a small team uses AI to ship a real internal product end-to-end as it was a product. The product is the methodology rendered legible.

XLessons

What I'm taking from this

01
The instrumentation is the research. A research platform that watches its own users at the level of every prompt, tool call, and file edit — and then produces a triaged queue of evidence-backed opportunities — collapses the gap between qualitative observation and quantitative prioritisation. This is the form factor I want for AI-native research broadly.
02
The same agent runtime that consumes a tool can produce evidence about it. Hooks make this nearly free. Once you have hooks, the question shifts from "how do we collect data?" to "what's worth listening for?" — which is a research question, not an engineering one.
03
AI agents can ship internal products end-to-end if you give them the right scaffolding. A shared design-system bootstrap, a glossary, a brief, four parallel agents on Vercel preview URLs. Hand-written code under 100 lines. The bottleneck is not "can the agents code." The bottleneck is the spec.
04
Honest threading beats clever threading. The heuristic scorer is wrong on topic switches. We didn't paper over it. The followup_reason makes the wrongness inspectable. A research tool that hides its own confidence is worse than one that surfaces it.

Built at Cleo over 3 days, May 2026, with two collaborators (backend + integration tests). AI collaborators: Claude Code (Opus 4.7), Cursor Composer (Sonnet 4.6), Anthropic API, OpenAI embeddings.