skillbundle
AGENTS.md3 starsChanged 42 days agoMITView on GitHub
This file is the primary guidance for AI coding agents (Claude Code, Codex, etc.) working in this repository. It is the single source of truth — CLAUDE.md just imports this file. SkillBundle is a web app for finding AI coding assistant skills and keeping track of the ones you use. It syncs the skills.sh catalog, adds search, filters, comparison, and GitHub repo matching on top, and lets users save skills into shareable bundles and follow changes to them. See PRODUCT.md…
- Reads credentials
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,700 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository4 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- public/llms.txtllms.txt
- panel-reviewSkill
- recapSkill
The file
We split this AGENTS.md into the rules it gives an agent
7 rules. About 0 are common, 1 is distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 14
Check it for planned work and deferred decisions, and add to it rather than letting ideas get lost in chat.
- Very specific: line 31
pnpm buildneeds a reachable Convex deployment: Every generateStaticParams calls fetchQuery (via lib/representative-params.ts), and … - Very specific: line 101
Keep the page component synchronous and pass the params promise down.
- Very specific: line 179
Categories are implemented: Every skill gets tags from a fixed list of 28 categories (Frontend, UI & Design, Testing & QA, …), assigned by …
- Very specific: line 199
Class names: Use cn() from lib/utils.ts (clsx + tailwind-merge)
- Very specific: line 200
Component variants: Use class-variance-authority (cva)
- Very specific: line 202
Convex functions: Use v validator from convex/values for all argument/return validation
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
AGENTS.md
This file is the primary guidance for AI coding agents (Claude Code, Codex, etc.)
working in this repository. It is the single source of truth — CLAUDE.md just
imports this file.
Project Overview
SkillBundle is a web app for finding AI coding assistant skills and keeping track of the ones you use. It syncs the skills.sh catalog, adds search, filters, comparison, and GitHub repo matching on top, and lets users save skills into shareable bundles and follow changes to them. See PRODUCT.md for the product context, positioning, and pricing rules, and docs/architecture.md for the routes.
Roadmap & ideas
Things we want to build, ideas, and parked decisions live in TODO.md. Check it for planned work and deferred decisions, and add to it rather than letting ideas get lost in chat.
Commands
pnpm dev— Start Next.js dev serverpnpm build— Production buildpnpm lint— Run ESLintpnpm test— Unit tests (vitest,tests/**/*.test.ts— Convex backend logic)pnpm e2e/pnpm e2e:ui— Playwright (e2e/**/*.spec.ts): instant-navigation, landmark, share-metadata, floating-bar-clearance and skill-page guards signed out, plus signed-in functional coverage ine2e/authenticated/npx convex dev— Start Convex dev server (runs alongside Next.js dev)npx convex deploy— Deploy Convex functions to production
Both pnpm dev and npx convex dev must be running during local development.
pnpm build needs a reachable Convex deployment. Every generateStaticParams
calls fetchQuery (via lib/representative-params.ts), and prerendering those
paths runs the 'use cache' loaders. A fresh clone without .env.local cannot
build. The hardcoded fallbacks in representative-params.ts harden param
selection, not the render.
Markdown-only pushes do not deploy. vercel.json runs
scripts/vercel-ignore-build.mjs, which skips the Vercel build when every file
changed since the last successful deploy is *.md. Each deploy resets the ISR
cache, so this saves real money. If the app ever reads a .md file at build or
run time, narrow that script's match first, or edits to that file will never
ship.
Two test suites, deliberately non-overlapping. pnpm test is vitest over
tests/**/*.test.ts; pnpm e2e is Playwright over e2e/**/*.spec.ts, against a
production build on port 3100. Don't put one kind of test in the other's
directory — the globs are what keep the runners apart. pnpm check is
format:check + lint + typecheck + unit tests; e2e is separate because it builds
the app.
Formatting is gated, so run pnpm format before committing. Prettier owns
every file except components/ui/cubby-ui/, which is vendored through
shadcn add and excluded in .prettierignore — formatting it would be
reverted by the next component update and break the gate on arrival.
components/charts/ used to be excluded for the same reason; it is now our own
code (see Charts below) and is formatted like everything else.
shadcn add @cubby-ui/style needs a manual pass over app/globals.css
afterwards, every time. app/globals.css is NOT in .prettierignore, so the
installer's four-space output fails format:check — run pnpm format. It also
runs an update-theme pass that echoes every non-color variable back into
@theme inline as --x: var(--x). Those are inert (a self-reference is a cycle,
and the real values live in the unlayered :root / .dark further down, which
outrank the theme layer either way) but they accumulate; delete them. Delete ONLY
exact self-references — --color-x: var(--x) entries are real aliases that
generate utilities, and --color-chrome: var(--chrome) in particular is what
makes bg-chrome work.
.gitattributes pins the working tree to LF and is load-bearing for that gate,
not housekeeping. core.autocrlf=true is the Windows default and rewrites files
as CRLF whenever git materialises them; Prettier's default endOfLine: "lf"
then rejects them. Which files are hit depends on which ones git last checked
out, so without the pin pnpm check passes or fails according to your recent
branch switches. If format:check ever fails on a file that looks correct,
check its line endings first.
Tech Stack
- Framework: Next.js 16 (App Router) with React 19
- Backend: Convex (database, serverless functions, cron jobs)
- Auth: Clerk (JWT-based, synced to Convex via webhooks)
- Styling: Tailwind CSS v4 with OKLch color system
- Package manager: pnpm
- UI components: Custom library in
components/ui/cubby-ui/built on Radix UI and Base UI primitives. Component docs available at https://www.cubby-ui.dev/llms.txt - Icons: HugeIcons (primary) and Lucide React
- Animations: Motion library (motion) for UI; charts animate through TanStack Charts' own motion renderer (see Charts below)
- Charts: TanStack Charts (
@tanstack/charts)
Architecture
This is a high-level map. The detailed, authoritative guides are:
- docs/architecture.md — frontend & platform: Next.js 16 static-first rendering + caching, the route inventory (static / ISR / dynamic), the Suspense-default-state pattern, Clerk auth wiring, the provider tree, data-fetching patterns, nuqs URL state, and Polar billing. Read this before any frontend / rendering / caching / auth work. Two rules from that guide that are easy to break without noticing, because direct page loads keep working either way:
- Catalog pages (
/[org],/[org]/[repo],/site/[source]) must notawait paramsabove their<Suspense>boundaries. Doing so empties the route's shared App Shell and makes every client navigation into it blocking. Keep the page component synchronous and pass theparamspromise down. - Error handling has three layers (
app/global-error.tsx,app/(main)/error.tsx,components/data-error-boundary.tsx). Use the innermost one that fits rather than addingtry/catchinside a Server Component — that swallows the error and losesretry(). - Restructuring a page means updating its
loading.tsx/ Suspense fallback in the same change. Nothing catches that drift — the e2e guards assert a shell commits instantly, not that it resembles the page — and a stale fallback reads to users as the skeleton being replaced by a second, different skeleton rather than as a bug. See docs/architecture.md §2. - A section that's expensive on the client usually belongs on the server, not
behind a deferral. Deferring keeps the cost and adds a loading phase. Only
genuinely per-interaction work (e.g. the shiki diff in
components/skill-history-row.tsx) should stay lazy.
e2e/instant-navigation.spec.ts guards the first one. See docs/architecture.md
§1, §14 and §15.
- docs/skill-lifecycle.md — backend skill pipeline: how skills enter the catalog, the sync / reconcile / curated / duplicate-detection jobs, "seen" + delisting rules, snapshots, and the
needs*work-set patterns. Read this before touching the sync or skill-lifecycle code. - docs/charts.md — the three charts and the TanStack Charts integration: how a definition is composed, what the hover overlay owns versus the library, the motion and density rules, and a long list of traps with the measurements behind them. Read this before touching any chart.
Frontend → backend
ClerkProvider wraps ConvexProviderWithClerk in the root layout (app/layout.tsx). Static-first: route shells prerender (CDN), and per-user/interactive data arrives over the authenticated Convex websocket via useQuery/useMutation (or useQuery(convexQuery(...)) through TanStack Query). Auth is Clerk, bridged to Convex by JWT; the proxy.ts middleware uses an inverted private-route list (/settings, /dev; /dashboard is public because signed-out visitors keep bundles in the browser, see docs/architecture.md §9) because the catch-all org routes shadow everything — see docs/architecture.md §3.
Convex backend (convex/) at a glance
Tables (schema.ts), grouped by concern:
- Skills catalog:
skills(full ~10 KB rows),skillSummaries(slim ~1.3 KB denormalized rows that lists/search/cards read),skillEmbeddings(vector search),skillAudits+skillSnapshots(security verdicts + install-count history),syncStats. - Sync / dedup support:
curatedOwnerSummaries,githubTreeCache,githubRepoResolution,repoFingerprintCache,wellKnownIndexes(per-domain skills-index probe results; what decides whether a site page can show an install command). - Version archive:
skillVersions(one row per detected SKILL.md change, raw file in_storage;isBaselinemarks a starting point rather than an edit). - Users & bundles:
users,bundles,repoMatchQuota(free-plan repo-match usage, one row per account). (bundleStatsandbundleStarswere removed — see the note at the end ofschema.ts.)
Modules, grouped by concern:
- Skill sync & lifecycle:
skills.ts(sync pipeline + catalog queries),reconcile.ts,curated.ts/curatedRefresh.ts,duplicates.ts,audits.ts,crons.ts, pluslib/*helpers (detailRefresh,skillHealth,source,appDay,pagination,github,skillsApi,embeddings). Documented in docs/skill-lifecycle.md. - Leaderboards & discovery:
leaderboards.ts(trending/hot),recommendations.ts(repo-fingerprint matching, plus the signed-outanalyzeRepoAnonymousthe site's server action calls),repoMatchQuota.ts(the free plan's monthly repo-match allowance; who is metered how isrepoMatchMeterinlib/repo-match.ts),tags.ts(category tagging with TypeSafe's Jev model; the category list islib/categories.ts, what each category means to the model islib/categoryDefinitions.ts). - Well-known sources:
wellKnown.ts(weekly probe of each well-known domain's skills index, at the root and under a fixed set of base paths). Read its header before touching anynpx skills addstring — the command for a well-known source is not derivable from the source, and the obvious form is one the CLI resolves to a GitHub repo. - Version archive & monitoring:
skillVersions.ts(read + write API over the change archive;freshness.tsdecides which SKILL.mds to re-check). - Bundles & social:
bundles.ts. - Users, auth & billing:
users.ts,http.ts(Clerk + Polar webhooks, Svix-validated),auth.config.ts,subscriptions.ts/plans.ts/polar.ts,rateLimits.ts(per-user limits on public actions that spend money or GitHub budget; read its header before changing a number or adding an app-wide limit) (+convex.config.tsregisters the@convex-dev/polarand@convex-dev/rate-limitercomponents). - Admin / dev:
devStats.ts(the/devdashboard stats),devSeed.ts,githubOnly.ts(admin add of skills that exist only on GitHub, not on skills.sh — see docs/skill-lifecycle.md "GitHub-only skills"),githubOnlyAudit.ts(read-only diagnostic: GitHub-only rows whose stored slug disagrees with their SKILL.md's frontmatter name),bindAudit.ts(read-only diagnostic: is the RIGHT SKILL.md bound to each skill — a different question fromgithubOnlyAudit.ts),devSeedFeed.ts(dev-only seeding for the dashboard's change feed).
This list is "at a glance", not exhaustive — but every module and table it NAMES should exist. It has twice pointed at files that had been deleted.
Crons (crons.ts)
Daily sync chain (syncSkills 06:00 UTC → curated 06:30 → snapshot prune 06:45 → reconcileUnseenSkills 07:00, with the discovery/content/audit/embedding pipeline chained off the sync), hourly + 30-min leaderboard refreshes (trending / hot), daily cache cleanups, and a weekly Sunday chain (resolve repo identities 08:00 → curated refresh 09:00 → re-resolve stale identities 10:00 → well-known index probe 11:00). Production-only (gated by CRONS_ENABLED).
Charts
Three charts, all built on TanStack Charts (@tanstack/charts): the sidebar
sparkline, the Stats tab's install-history chart, and the compare page's multi-line
chart. Shared pieces live in components/charts/; each chart file owns its own
defineChart definition, and components/charts/charts.css holds the styling
for nodes the library renders and we never author.
docs/charts.md is the authoritative guide — read it before touching any chart. It is mostly a list of traps, each with the measurement behind it, and the code is written short on the assumption you have read them.
One that costs the most time if you miss it: the library ships its own docs and
skills inside the package, at node_modules/@tanstack/charts/docs/ and
.../skills/, indexed by llms.txt. Read those rather than relying on memory
or a docs mirror. They match the installed version, and this is a young library
that moves.
Category and technology tagging
Categories are implemented. Every skill gets tags from a fixed list of 28
categories (Frontend, UI & Design, Testing & QA, …), assigned by TypeSafe's Jev model
in convex/tags.ts and documented in docs/skill-lifecycle.md "Category
tagging". They drive the home page's Category filter and the Categories block
in the skill page sidebar. They are deliberately not shown on catalog rows.
To change what a category means, edit convex/lib/categoryDefinitions.ts. Most
fixes are a sharper "doesNotCount" line, because the model reads literally.
Try the change on a sample (tags:markAllForTagging '{"limit": 200}') before
bumping CATEGORIES_VERSION and re-tagging everything. Category keys are
stored on rows and in the search index; labels are display-only.
Technology tags (Next.js, Supabase, …) are not implemented.
components/skill-card.tsx still has an optional technologies prop that
nothing populates. The planned approach is in TODO.md: code finds technology
names in the SKILL.md, and Jev judges which ones the skill is actually about.
Conventions
- Path alias:
@/*maps to project root - Class names: Use
cn()fromlib/utils.ts(clsx + tailwind-merge) - Component variants: Use
class-variance-authority(cva) - UI components config: See
components.jsonfor shadcn/ui style ("new-york"), icon library, and path aliases - Convex functions: Use
vvalidator fromconvex/valuesfor all argument/return validation - One-shot repairs and backfills (hand-run once via
npx convex run, then dead) go in their ownconvex/<name>Repair.ts, with a DELETE-ON-COMPLETION header naming the commands and the exit condition, and aTODO.mdentry that owns the deletion. Not inline in the module they repair. Reason, from Aug 2026: a one-shot documented only in its own header was cloned into a near-duplicate the next day (6e12f16→dcb61f5) because nothing outside the file recorded that it existed.skills.tsstill carries several that pre-date this rule (backfillIsDelistedFalse,backfillLastSeenInApi,backfillNeedsRepoResolution,backfillArchiveBaselines) — don't add another. Their presence is the argument for the rule, not an exception to it: none is called by anything, and what records that each is finished is scattered — a schema comment for two (schema.ts), a migration note for the same two (docs/skill-lifecycle.md), aTODO.mdentry plusfreshness.tsprose forbackfillArchiveBaselines, and nothing at all outside its own file forbackfillNeedsRepoResolution. No single place says which are retirable, which is exactly what the rule above fixes.
<!-- BEGIN:nextjs-agent-rules -->This is NOT the Next.js you know
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ (resolved from this file's directory; in monorepos the next package may not be visible from the repo root) before writing any code. Heed deprecation notices.
This block is written and re-added by next dev — verify at node_modules/next/dist/server/lib/generate-agent-files.js. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.
<!-- END:nextjs-agent-rules -->Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

