<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ismael Briasco</title>
    <description>The latest articles on DEV Community by Ismael Briasco (@briascoi).</description>
    <link>https://dev.to/briascoi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3880480%2F08b4871b-cc4b-4b28-8fcd-56ffa70db229.jpg</url>
      <title>DEV Community: Ismael Briasco</title>
      <link>https://dev.to/briascoi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/briascoi"/>
    <language>en</language>
    <item>
      <title>Building skillgrab: auto-detecting stacks across JS, Python, Go, mobile and infra to install AI agent skills in one command</title>
      <dc:creator>Ismael Briasco</dc:creator>
      <pubDate>Wed, 15 Apr 2026 12:29:25 +0000</pubDate>
      <link>https://dev.to/briascoi/building-skillgrab-auto-detecting-stacks-across-js-python-go-mobile-and-infra-to-install-ai-1276</link>
      <guid>https://dev.to/briascoi/building-skillgrab-auto-detecting-stacks-across-js-python-go-mobile-and-infra-to-install-ai-1276</guid>
      <description>&lt;p&gt;How I built a zero-config CLI that scans any project and installs only the AI agent skills that match — covering the architecture, the gotchas, and what I'd build next.&lt;/p&gt;

&lt;p&gt;skills.sh hosts 90,000+ skills for AI coding agents like Claude Code. Picking the right ones for &lt;em&gt;your&lt;/em&gt; project is manual: you scroll, you guess, you &lt;code&gt;npx skills add&lt;/code&gt; one at a time, and you end up with a &lt;code&gt;~/.claude/skills/&lt;/code&gt; either bloated or empty.&lt;/p&gt;

&lt;p&gt;I wanted to type one command in any project directory and have the right skills installed. So I built &lt;strong&gt;&lt;a href="https://github.com/briascoi/skillgrab" rel="noopener noreferrer"&gt;skillgrab&lt;/a&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skillgrab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. It scans your project, detects your stack, and installs matching skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape
&lt;/h2&gt;

&lt;p&gt;Three steps, zero config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx skillgrab
  ├─ Scan files (package.json, requirements.txt, pubspec.yaml,
  │              go.mod, Dockerfile, README, …)
  ├─ Search skills.sh + validate against GitHub
  └─ Multi-select picker → npx skills add
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A typical run on a Next.js + Supabase + Stripe SaaS surfaces ~10 ranked skills. Trusted owners (Anthropic, Vercel, Supabase, Stripe, Clerk, OpenAI, …) get a star and a popularity boost. Stale entries from the search API get dropped before the user sees them. One clone per repo. One ✓ per skill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project dir
    │
    ▼
┌─ detect/  ────────────────────┐
│   node.ts    package.json     │
│   python.ts  requirements.txt │
│   mobile.ts  pubspec.yaml     │
│   backend.ts go.mod, Cargo…   │
│   infra.ts   Dockerfile, …    │
│   context.ts README/docs      │
└─────────────┬─────────────────┘
              ▼
   skills.sh /api/search (live)
              │
              ▼
   rank: trusted boost + log10(installs)
              │
              ▼
   dedupe by skill name
              │
              ▼
   GitHub trees API validation
   (drop stale slugs)
              │
              ▼
   @clack/prompts multi-select
              │
              ▼
   npx skills add (grouped by repo)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each detector is a tiny pure function: &lt;code&gt;(rootDir) =&amp;gt; Signal[]&lt;/code&gt;. The CLI runs them in parallel, dedupes by key, and feeds the resulting signals into the registry layer. The registry queries skills.sh's JSON API per signal, scores results, and gates them through GitHub validation. The install step groups by source repo so a single clone covers N skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five gotchas that took me longer than they should have
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. skills.sh is a Next.js SPA
&lt;/h3&gt;

&lt;p&gt;The first version of skillgrab tried to scrape &lt;code&gt;/search?q=...&lt;/code&gt;. Returned 0 results every time. The HTML payload is just a bootstrap loader; results render client-side. The actual JSON endpoint is &lt;code&gt;/api/search?q=...&lt;/code&gt;, which I found by &lt;code&gt;curl&lt;/code&gt;-ing what looked like API paths until one returned JSON. Lesson: when a SPA has a search box, there's almost always a private JSON endpoint behind it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The curated fallback was a footgun
&lt;/h3&gt;

&lt;p&gt;When the API returned nothing, I fell back to a hand-written map of &lt;code&gt;tech → owner/repo&lt;/code&gt; slugs. I'd guessed half of them. &lt;code&gt;npx skills add growth/skills&lt;/code&gt; tried to clone &lt;code&gt;github.com/growth/skills.git&lt;/code&gt; (404). Skills.sh's installer turns slugs into git clones, so a wrong slug doesn't fail gracefully — it errors out mid-flow. &lt;strong&gt;Removed the curated fallback entirely.&lt;/strong&gt; If the API is down, return &lt;code&gt;[]&lt;/code&gt;. Better silent than wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;code&gt;--skill a,b,c&lt;/code&gt; is one literal name
&lt;/h3&gt;

&lt;p&gt;skills.sh's CLI accepts &lt;code&gt;--skill &amp;lt;name&amp;gt;&lt;/code&gt;. I assumed the plural form &lt;code&gt;&amp;lt;skills&amp;gt;&lt;/code&gt; in the help meant comma-separated. It does not. It treats &lt;code&gt;"a,b,c"&lt;/code&gt; as one filename to match. So when I asked it to install &lt;code&gt;copywriting,social-content,content-strategy&lt;/code&gt; from a repo that had all three, it said "no matching skills found" — and listed all three in the available list right below. The fix: repeated flags. &lt;code&gt;--skill a --skill b --skill c&lt;/code&gt;. One clone, three installs.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The search API returns &lt;code&gt;skillId&lt;/code&gt;s that don't exist
&lt;/h3&gt;

&lt;p&gt;skills.sh's search uses fuzzy matching. Sometimes it returns slugs like &lt;code&gt;apify/agent-skills/apify-content-analytics&lt;/code&gt; — a plausible-sounding skill, but the apify repo only has 4 skills, none of them named that. The slug came from substring matches against READMEs, not from real skill manifests. So skillgrab now validates each candidate before committing it to the install plan: HEAD the GitHub trees API for the repo, check if &lt;code&gt;&amp;lt;skillId&amp;gt;/SKILL.md&lt;/code&gt; exists. If not, drop it.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Plugin-structured repos hide skills under nested folders
&lt;/h3&gt;

&lt;p&gt;Validating naive paths like &lt;code&gt;&amp;lt;owner&amp;gt;/&amp;lt;repo&amp;gt;/&amp;lt;skillId&amp;gt;/SKILL.md&lt;/code&gt; only covered flat repos. &lt;code&gt;anthropics/knowledge-work-plugins&lt;/code&gt; puts skills under &lt;code&gt;&amp;lt;plugin&amp;gt;/skills/&amp;lt;id&amp;gt;/SKILL.md&lt;/code&gt; — &lt;code&gt;sales/skills/draft-outreach/SKILL.md&lt;/code&gt;, &lt;code&gt;bio-research/skills/instrument-data-to-allotrope/SKILL.md&lt;/code&gt;. The validator now fetches the recursive tree once per repo (cached) and checks if any path &lt;em&gt;ends with&lt;/em&gt; &lt;code&gt;&amp;lt;skillId&amp;gt;/SKILL.md&lt;/code&gt;. Works for both shapes. Honors &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; to bypass the 60/hr unauth limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd build next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;--watch&lt;/code&gt; mode that re-scans on &lt;code&gt;package.json&lt;/code&gt; changes.&lt;/li&gt;
&lt;li&gt;Per-language refinements: Rails versions, Go module categories, Astro vs SvelteKit etc.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;skillgrab list&lt;/code&gt; command that just shows the plan as JSON, for piping into other tools.&lt;/li&gt;
&lt;li&gt;An MCP server wrapper, so coding agents can call skillgrab via MCP instead of shell.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/your-project
npx skillgrab &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PRs welcome — especially new stack detectors. Each detector lives in &lt;code&gt;src/detect/&lt;/code&gt; and is ~50 lines.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/briascoi/skillgrab" rel="noopener noreferrer"&gt;github.com/briascoi/skillgrab&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Landing:&lt;/strong&gt; &lt;a href="https://briascoi.github.io/skillgrab/" rel="noopener noreferrer"&gt;briascoi.github.io/skillgrab&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/skillgrab" rel="noopener noreferrer"&gt;npmjs.com/package/skillgrab&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>cli</category>
      <category>claude</category>
    </item>
  </channel>
</rss>
