Finds, scores, and ranks the best library, SDK, or tool for your exact stack — no Reddit threads, no outdated blogs. 4-tier search, deterministic scoring, built-in security gate. Works with Claude Code, Claude.ai, Codex & Antigravity.
SaferSkills independently audited SKILLmama (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Recommended model: Use the most capable model available to your agent (e.g. Claude Sonnet or better, GPT-4.1 or better, Gemini 2.5 Pro or better). This skill runs multiple web searches and applies a scoring formula — a capable model produces significantly better results.
Trigger: Use this skill when the user is asking to select, discover, or rank technical tools, libraries, or integrations — specifically:
/skillmama with no argumentsDo NOT activate for:
If the user named a specific capability (e.g. "auth", "vector DB", "job queue"): → Flow A — go to Phase 0.
If the user typed `/skillmama` with no arguments, or said "scan my project" / "what am I missing" / gave no specific capability: → Flow B — go to Phase B1.
Extract:
If the capability is genuinely ambiguous, ask one clarifying question and stop.
Read these files if present: package.json / pyproject.toml / go.mod / Cargo.toml / composer.json Dockerfile, docker-compose.yml, .env.example vercel.json, fly.toml, railway.toml, render.yaml README.md, SETUP.md, DEPLOY.md / DEPLOYMENT.md, and any agent instructions file present (CLAUDE.md, AGENTS.md, etc.)
Extract:
If the user stated a stack inline (e.g. "my FastAPI app") and Phase 1 finds no trace of it (no matching language/framework files in the scanned directory, or the directory looks unrelated — e.g. it's this skill's own repo, a docs repo, empty), do not silently proceed on an empty scan. Say so and ask which directory to scan:
I didn't find [stated stack] in this directory — this doesn't look like that project. Want me to scan a different folder, or should I search based on what you told me with no local verification?
Proceed with the user-stated stack either way once they answer (or confirm searching stack-only is fine).
Only if the user stated NO constraints in their original request. If they already constrained the search (e.g. "find me an open-source job queue"), skip this phase entirely and continue to Phase 2.
Ask ONE constraint question, then STOP and wait for the reply.
If Phase 1 detected a stack, make the question informed by it:
I see you're on [detected stack]. Before I search — any constraints? (e.g. self-hosted, open-source only, free tier, must integrate with [detected tool]). Reply "none" to search with no filters.
If Phase 1 detected nothing (no project files, or empty scan), ask generically — do not reference a stack:
I couldn't detect your stack from project files. Before I search — any constraints? (e.g. language/framework, self-hosted, open-source only, free tier). Reply "none" to search broadly.
Set constraints from the reply (treat "none" as no filters), then continue to Phase 2. Ask this once — never re-prompt.
Then continue to Phase 2 below.
Before reading any files, output this notice to the user:
SKILLmama — Project Scan initiated. I will read your package files, config files, and a sample of source files using read-only operations (find,ls, file reads). No files will be modified or deleted. Your agent will prompt for permission before each file read or shell command.
Then read all of the following that are present:
Package & dependency files: package.json, pyproject.toml, requirements.txt, go.mod, Cargo.toml, composer.json, Gemfile
Config & infrastructure: Dockerfile, docker-compose.yml, .env.example, vercel.json, fly.toml, railway.toml, render.yaml
Project docs: README.md, SETUP.md, DEPLOY.md / DEPLOYMENT.md, and any agent instructions file present (CLAUDE.md, AGENTS.md, etc.)
Source structure (list only, do not read every file): find . -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.py" -o -name "*.go" \) | grep -v node_modules | grep -v .git | head -60 ls -1 src/ app/ lib/ pages/ api/ (whichever exist)
Read 2–4 representative source files to understand what the app actually does (entry point, a route handler, a model file).
Build a Stack Profile:
Language: [primary language(s)]
Framework: [e.g. Next.js 14, FastAPI, Express]
Database: [e.g. Postgres via Prisma, none detected]
Auth: [e.g. NextAuth, none detected]
Caching: [e.g. Redis, none detected]
AI/LLM: [e.g. OpenAI SDK, none detected]
Queue/Jobs: [e.g. BullMQ, none detected]
Search: [e.g. Elasticsearch, none detected]
Storage: [e.g. S3 via aws-sdk, none detected]
Email: [e.g. Resend, none detected]
Payments: [e.g. Stripe, none detected]
Observability: [e.g. Sentry, none detected]
Testing: [e.g. Vitest, none detected]
Deployment: [e.g. Render (web service, no persistent disk found), Vercel (serverless), self-hosted Docker w/ volumes, undetected]For each common capability category, check the Stack Profile. Only flag if genuinely absent.
Common categories to check:
For each gap, assign severity:
Present findings and STOP — do not proceed until the user replies.
Stack detected: [one-line summary, e.g. "TypeScript / Next.js 14 / Postgres / no auth"]
Capability gaps found:
| # | Gap | Severity | Why it matters for your stack |
|---|---|---|---|
| 1 | [gap] | High | [one sentence] |
| 2 | [gap] | Medium | [one sentence] |
| 3 | [gap] | Low | [one sentence] |
A few quick questions before I search:
STOP. Do not proceed until the user has replied.
Once the user replies, set:
capability = their chosen gap(s)constraints = anything from Q2If they picked multiple gaps, run the shared pipeline once per gap and present each as its own SKILLmama Results block.
Then jump directly to Phase 2 below (stack is already known — skip Phase 0 and Phase 1).
From Phase 0 + Phase 1, produce 3–5 search terms combining capability + stack. Example: ["qdrant python", "pgvector fastapi", "chroma vector db"]
Search each tier in order. Collect candidates. Stop a tier early only if you already have 8+ strong candidates.
WebSearch: site:github.com [search_term] stars:>500 WebSearch: site:github.com [capability] [language] open source For each promising repo, extract: stars, last commit date, contributors, open issues, releases. Also check: does this repo contain a SKILL.md? If yes, tag has_own_skill: true.
WebSearch: MCP server [capability] WebSearch: model context protocol [capability] tool WebSearch: site:github.com modelcontextprotocol [capability]
npm: WebSearch: site:npmjs.com [capability] [framework] PyPI: WebSearch: site:pypi.org [capability] Extract: weekly downloads, latest version date.
WebSearch: [capability] starter template [stack] WebSearch: awesome [capability] github list
Evaluate each library candidate. Run both checks below against live data. Do not answer them from search snippets or model recall.
Check 1 — Known advisories (OSV.dev, all ecosystems).
curl -s -X POST "https://api.osv.dev/v1/query" \
-d '{"package":{"name":"<pkg>","ecosystem":"<npm|PyPI|Go|crates.io>"},"version":"<version-you-would-recommend>"}'Severity is vulns[].database_specific.severity (CRITICAL / HIGH / MODERATE / LOW). The fix, when one exists, is the fixed event under vulns[].affected[].ranges[].events[]. Two traps:
PYSEC-* records with severity: UNKNOWN that duplicate a GHSA-* record for the same flaw. Dedupe on aliases and read severity off the GHSA twin before concluding a severity is unknown.Check 2 — Publisher continuity (npm, crates.io).
Publish rights changing hands is the supply-chain failure advisory scanning cannot see, because advisories only exist after public disclosure. In the event-stream case this signal was available on 2018-09-05, while the advisory did not land until 2018-11-26.
curl -s "https://registry.npmjs.org/<pkg>" | python3 -c "
import json,sys,datetime
BOTS={'GitHub Actions','semantic-release-bot','npm','types','oss-bot','npm-cli-ops','react-bot','renovate-bot'}
d=json.load(sys.stdin); t=d.get('time',{})
vs=sorted([(v,m) for v,m in d.get('versions',{}).items() if v in t], key=lambda x: t[x[0]])
h=[(v,m.get('_npmUser',{}).get('name'),t[v][:10]) for v,m in vs]
h=[x for x in h if x[1] and x[1] not in BOTS]
seen=set(); last=None
for i,(v,who,when) in enumerate(h):
if seen and who not in seen and not (set(seen) & {x[1] for x in h[i:]}): last=(h[i-1],(v,who,when))
seen.add(who)
if not last: print('publisher: no handoff (solo, team rotation, or CI-published)')
else:
mo=(datetime.date.today()-datetime.date.fromisoformat(last[1][2])).days/30.44
print(f'HANDOFF: {last[0][1]} (last @{last[0][0]}) -> {last[1][1]} (@{last[1][0]}, {last[1][2]}, {mo:.0f}mo ago)' if mo<12
else f'handoff {mo:.0f}mo ago - stale, do not report')
"Four rules make this a signal instead of noise. Each was wrong in an earlier revision and is load-bearing:
GitHub Actions is a CI migration, not a handoff. Versions with no _npmUser must be dropped, not treated as a publisher named ?. Keep the bot list literal: a regex generalization was measured against it across 98 packages and scored identically (7.1% both), so it is complexity with no benefit. Org automation accounts outside the list (typescript-deploys -> microsoft1es) can still produce roughly 1 false positive per 100, obvious on sight because the output names both publishers.This catches handoffs, not account takeovers. In the ua-parser-js, rc, and coa compromises the attacker published under the legitimate maintainer's name, so publisher continuity reads clean and only Check 1 catches them, after disclosure. Say so rather than implying takeover coverage.
crates.io runs the same check, adapted to its shape:
curl -s -H "User-Agent: skillmama (contact: <your-contact-info>)" "https://crates.io/api/v1/crates/<crate>" | python3 -c "
import json,sys,datetime
d=json.load(sys.stdin)
vs=sorted(d.get('versions',[]), key=lambda v: v['created_at'])
h=[(v['num'], (v.get('published_by') or {}).get('login'), v['created_at'][:10]) for v in vs]
h=[x for x in h if x[1]]
seen=set(); last=None
for i,(v,who,when) in enumerate(h):
if seen and who not in seen and not (set(seen) & {x[1] for x in h[i:]}): last=(h[i-1],(v,who,when))
seen.add(who)
if not last: print('publisher: no handoff (solo, team rotation, or trusted-publishing/CI)')
else:
mo=(datetime.date.today()-datetime.date.fromisoformat(last[1][2])).days/30.44
print(f'HANDOFF: {last[0][1]} (last @{last[0][0]}) -> {last[1][1]} (@{last[1][0]}, {last[1][2]}, {mo:.0f}mo ago)' if mo<12
else f'handoff {mo:.0f}mo ago - stale, do not report')
"crates.io needs no separate bot list: published_by is null both for trusted publishing (a CI-based release with no human account — crates.io's equivalent of npm's GitHub Actions) and for versions published before crates.io tracked publishers at all, so a null login is dropped the same way a missing _npmUser is. The four rules above apply unchanged — in particular, rustls rotates releases among an active team (ctz, djc, cpu) the same way express/lodash/chalk do on npm, so "any human-to-human change" is still the wrong test. crates.io's crawler policy 403s requests with no descriptive User-Agent; npm's registry has no such requirement.
PyPI and Go expose no per-release uploader, so report N/A (unsupported ecosystem) for candidates on those registries. Never imply it was checked.
DISCARD (set security: "BLOCKED", add security_note when the rule below sets one) if:
fixed version available — set security_note to the advisory's summary, including any trigger condition (specific mode, flag, or endpoint) verbatim from OSV, so the user can judge whether their actual usage is exposed. If OSV states no precondition, don't invent one. This still blocks regardless of the condition — the note adds context, it does not narrow the rule.WARN (set security: "WARN", add security_note) if:
If OSV or the registry is unreachable, report that check N/A (unverified) for the candidate in Phase 5. Never let an unverified candidate read as having passed.
FLAG (set sqp, add security_note, do NOT discard) if:
A candidate can match several rules at once. DISCARD wins outright over WARN and FLAG — a candidate is never downgraded to WARN or FLAG because a lesser rule also matched. WARN and FLAG are independent of each other; report both if both apply.
REQUIRED — do not skip. Run these searches for every candidate from Tiers 1–4 before moving to Phase 3.7. If no results are found, write "No companion skills found" and continue. Never silently omit this phase.
For each candidate collected from Tiers 1–4: WebSearch: site:skills.sh [candidate_name] WebSearch: site:terminalskills.io/skills [candidate_name] WebSearch: site:skillsmp.com [candidate_name] WebSearch: site:github.com "SKILL.md" [candidate_name]
For any match found, note it as a companion skill for that candidate. If found on terminalskills.io, note its reliability rating (SAFE / SUSPICIOUS / MALICIOUS) — treat SUSPICIOUS or MALICIOUS as an automatic Phase 3.7 DISCARD. skillsmp.com has no vetting or reliability rating (auto-indexed from public GitHub repos) — treat a skillsmp.com match as a pointer to go verify the underlying GitHub repo directly, not as a trust signal on its own.
Evaluate each skill found in Phase 3.6. Skills are agent instruction sets — a malicious skill can directly hijack agent behavior.
DISCARD if:
FLAG (do NOT discard) if:
WARN if:
A candidate can match several rules at once. DISCARD wins outright: it is never softened to a FLAG because a lesser rule also matched. WARN and FLAG may both apply to the same candidate; report both.
Skip any candidate marked BLOCKED from Phase 3.5.
Skip any candidate whose package name already appears in the Stack Profile's detected dependencies — mark it ALREADY PRESENT instead of scoring it. Don't re-recommend something the project already has installed.
Total Score = (Compatibility × 0.40) + (Popularity × 0.30) + (Maintenance × 0.15) + (Simplicity × 0.15)Each factor scored 1–10:
Compatibility (40%) — fit to detected stack
Before scoring, verify — don't just infer. For each candidate still in play, check what it actually requires (API key, CLI, running service, env var) against the local environment: read .env.example for the key name, check which [cli] for a required tool, look for a config file the service needs. This is the same read-only posture as Phase B1 — no writes.
REDIS_URL — not found in .env.example")If a required dependency can't be verified either way (e.g. no way to check a hosted service from project files), don't penalize — note it as unverified instead.
Deployment Persistence Check — for any candidate whose normal operation stores data locally, in-process, or on-disk (embedded databases, in-process vector stores, SQLite, local file caches — anything that isn't a separately-hosted service reached over the network):
fly.toml → persistent only if it has a [[mounts]] sectionrailway.toml/railway.json → persistent only if a volume is configuredrender.yaml → persistent only if it has a disk: block; Render's default web service disk is ephemeralvercel.json present, or the stack is otherwise serverless/functions-based → always ephemeral, regardless of configdocker-compose.yml → persistent only if the service has a volumes: mapping to the data path the candidate would userender.yaml; data will be lost on restart/redeploy."Popularity (30%) — from github_stars + weekly_downloads
Maintenance (15%) — from last commit date
Verify per candidate, don't estimate from general knowledge of the org/project. Check the repo's releases/commits page (or the "Updated" date from Tier 1's GitHub search) for each candidate still in play before scoring. If a specific last-commit date genuinely can't be found, mark that candidate's Maintenance N/A (unverified) in the Phase 5 table rather than assigning a number — do not present an estimated score with the same confidence as a verified one.
Simplicity (15%) — from install command + setup effort
If a field is unknown, mark it N/A and weight the remaining factors proportionally.
Capability: [capability] Stack: [stack] Sources searched: Tier 1 (GitHub) · Tier 2 (MCP) · Tier 3 (npm/PyPI) · Tier 4 (Templates) · Skills (skills.sh + TerminalSkills.io + SkillsMP + GitHub SKILL.md)
Scoring all candidates against [stack]:
| Candidate | Compat | Pop | Maint | Simple | Score |
|---|---|---|---|---|---|
| [Name] | X | X | X | X | X.X |
#1 — [Name] · Score: X.X/10
[One sentence: what it is and why it wins for this stack]
[install_cmd]_(omit any that don't apply)_
#2 — [Name] · Score: X.X/10
[One sentence]
#3 — [Name] · Score: X.X/10
[One sentence]
| Name | Score | Why not #1 | Links |
|---|---|---|---|
| [Name] | X.X | [brief reason] | gh · npm |
| [Name] | ALREADY PRESENT | Already in your stack (found in [package.json / etc.]) | gh |
If a candidate has a Smithery link, highlight it:
[Name] — Install as an MCP tool for direct AI integration. [install_cmd] Smithery · GitHub_Omit this section if Phase 3.6 + 3.7 returned no passing results._
If any library has has_own_skill: true:
[Library Name] ships its own skill:npx skills add [owner/repo]orterminal-skills install [skill-name]skills.sh · TerminalSkills.io · SkillsMP · GitHub
For each companion skill where security != BLOCKED:
[Skill Name] — helps you work with [library]npx skills add [owner/repo]orterminal-skills install [skill-name]skills.sh · TerminalSkills.io · SkillsMP · GitHub Security: [PASS | ⚠️ SQP-1/2/3 — finding] — TerminalSkills.io rating: [SAFE, if listed]
ALREADY PRESENT in Also Considered instead.Security: line on each candidate in Phase 5.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.