Files
skillhub/CLAUDE.md
airano 4212b5ba47 sync: stale skill detection, sentry filtering, claim removal, review improvements
Stale Detection:
- Detect skills removed/moved from GitHub (3 consecutive 404s threshold)
- Hide stale skills from browse/search, show warning banner on detail page
- Serve cached files with isStale flag when GitHub returns 404
- Add stale-check crawler command for batch verification
- CLI shows warning when installing stale skills from cache

Sentry & Error Handling:
- Filter browser extension errors and add denyUrls
- Anti-inflation measures and sentinel recalibration for curation

Claim & Removal:
- Enhanced ClaimForm with repo-level removal support
- Add repo-removal-request API endpoint with tests
- Improved owner page with bilingual content

Review Pipeline:
- Review version and reviewer tracking in submit API
- Source format filter for pending reviews
- Updated review tests

Other:
- Updated i18n strings (en/fa)
- BrowseFilters improvements
- Dockerfile updates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 05:59:26 +03:30

125 lines
5.0 KiB
Markdown

# CLAUDE.md
## Project Overview
SkillHub is an open-source marketplace for **Agent Skills** — folders containing a `SKILL.md` file with instructions that AI agents can load dynamically.
**Live Site:** https://skills.palebluedot.live | **Status:** Production (`GET /api/stats`)
**Components:**
- **Web App** (`apps/web`): Next.js 15 marketplace
- **CLI** (`apps/cli`): Skill installer (`npm install -g skillhub`)
- **Indexer** (`services/indexer`): GitHub crawler
- **Packages** (`packages/*`): Core logic, DB, UI components
## Common Commands
```bash
pnpm install # Install dependencies
pnpm dev # Start all apps
pnpm --filter @skillhub/web dev # Start only web app
pnpm build # Build all packages
pnpm test # Run all tests (248 total)
pnpm --filter @skillhub/web test:e2e # E2E tests (requires running app)
pnpm db:push # Push schema changes
docker compose up -d # Start all services
```
## Architecture
```
skillhub/
├── apps/
│ ├── web/ # Next.js 15 + App Router + next-intl (i18n)
│ └── cli/ # Commander.js CLI, builds with tsup
├── packages/
│ ├── core/ # SKILL.md parser, validator, security scanner
│ ├── db/ # Drizzle ORM schema and queries
│ └── ui/ # Shared shadcn/ui components
├── services/
│ └── indexer/ # BullMQ worker for GitHub crawling
└── scripts/ # Database initialization scripts
```
## Database
**Schema files** (keep in sync):
- `scripts/init-db.sql` — SQL schema
- `packages/db/src/schema.ts` — Drizzle ORM schema
- `scripts/categories.sql` — Production categories
- `scripts/seed-data.sql` — Dev sample data
**Caching:** Skill files cached in `cached_files` JSONB column, invalidated when `commitSha` changes.
## Important Patterns
### Next.js 15 Async Params
`params` and `searchParams` are Promises:
```typescript
export default async function Page({ params }: { params: Promise<{ locale: string }> }) {
const { locale } = await params;
}
```
### i18n (next-intl)
Routes use `[locale]` segment. Use `setRequestLocale(locale)` for static rendering.
### Dynamic Rendering
Add `export const dynamic = 'force-dynamic'` to pages that fetch from database.
### Package Imports
- `skillhub-core` — Parser/validator
- `@skillhub/db` — Database
- `@skillhub/ui` — UI components
### API Route Pattern
Skill IDs = `owner/repo/skill-name`. Use catch-all: `/api/skills/[...id]/route.ts`
### CLI Skill ID Encoding
```typescript
const encodedPath = id.split('/').map(encodeURIComponent).join('/');
```
### Meilisearch IDs
Sanitized: `anthropics/skills/pdf``anthropics__skills__pdf`
## Environment Variables
`DATABASE_URL`, `REDIS_URL`, `GITHUB_TOKEN`, `MEILI_URL` (optional), `MEILI_MASTER_KEY`, `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, `AUTH_SECRET`
## Indexer
```bash
docker compose exec indexer node dist/crawl.js full # Full crawl
docker compose exec indexer node dist/crawl.js incremental # Last 24h
docker compose exec indexer node dist/crawl.js sync-meili # Sync to Meilisearch
docker compose exec indexer node dist/crawl.js deep-scan # Scan discovered repos
docker compose exec indexer node dist/crawl.js add-repo <owner/repo> # Manually add a repo to DB
docker compose exec indexer node dist/crawl.js process-add-requests # Process user-submitted add requests
```
### Database Migration (container)
```bash
# Add new columns (run when schema changes are deployed)
docker compose exec db psql -U skillhub -d skillhub -c "ALTER TABLE skills ADD COLUMN IF NOT EXISTS is_owner_claimed boolean NOT NULL DEFAULT false;"
docker compose exec db psql -U skillhub -d skillhub -c "ALTER TABLE discovered_repos ADD COLUMN IF NOT EXISTS is_blocked boolean NOT NULL DEFAULT false;"
docker compose exec db psql -U skillhub -d skillhub -c "CREATE INDEX IF NOT EXISTS idx_skills_owner_claimed ON skills(is_owner_claimed) WHERE is_owner_claimed = true;"
docker compose exec db psql -U skillhub -d skillhub -c "CREATE INDEX IF NOT EXISTS idx_discovered_repos_blocked ON discovered_repos(is_blocked) WHERE is_blocked = true;"
```
## Security
Status stored in `security_status` column: **PASS** (green) / **WARNING** (yellow) / **FAIL** (red). Indexer scans for dangerous commands, prompt injection, and data exfiltration.
## Critical Files
| Category | Files |
|----------|-------|
| Database | `packages/db/src/schema.ts`, `packages/db/src/queries.ts` |
| API Routes | `apps/web/app/api/skills/route.ts`, `apps/web/app/api/skill-files/route.ts` |
| Auth | `apps/web/lib/auth.ts`, `apps/web/components/AuthButton.tsx` |
| Caching | `apps/web/lib/cache.ts` (Redis with TTL) |
| Rate Limiting | `apps/web/lib/rate-limit.ts` |
| Indexer | `services/indexer/src/crawler.ts`, `services/indexer/src/strategies/` |
| CLI | `apps/cli/src/commands/install.ts`, `apps/cli/src/utils/api.ts` |