@solidprofessorhub/* packages instead of hand-rolled implementations. Run /shelf in Claude Code to get an HTML report of what to swap.
Developers hand-roll code that already exists in shared packages because:
<button> feels faster than looking up the component APIThe result: inconsistent UI, duplicated types, missed security policies (like PII scrubbing in observability), and more code to maintain.
Proactive guidance — loaded when writing code
Reactive audit — run after code is written
# Scan entire app
/shelf
# Scan specific path
/shelf app/components/course/
# Scan specific file
/shelf app/components/course/CourseSectionsList.vue
Shelf generates two outputs:
shelf-report.html at repo root, auto-opens in browserShelf never edits files or blocks anything. It reports findings — you decide what to adopt.
The generated shelf-report.html has four main sections:
At-a-glance counts: swaps to make, available-but-unused, and installed shared packages.
Shows installed vs latest for each @solidprofessorhub/* package. Highlights outdated packages with upgrade notes.
Grouped by package (shared-components, icons, tokens, etc.). Each finding shows before → after code with file:line reference.
Installed capabilities you're not taking advantage of — often the most valuable section for discovery.
Use the filter chips at the top to focus on one category at a time. Click through file references to locate code in your editor.
| Category | Detects | Suggests |
|---|---|---|
| shared-components | Raw <button>, <input>, <select>, hand-built modals |
BaseButton, BaseTextInput, TextField, FormModal, etc. |
| icons | FontAwesomeIcon for tokened icons | BaseIcon (angle-down, magnifying-glass, xmark, etc.) |
| tokens | Hardcoded hex colors, Tailwind arbitrary values | Design token classes (text-neutral-90, bg-primary-50) |
| http | axios, raw fetch for same-origin mutations | useHttp().postJson(), useHttp().getJson() |
| auth | localStorage token access, manual JWT parsing | useAuth().token, useAuth().isLoggedIn |
| types | Local interfaces duplicating shared types | Import from @solidprofessorhub/types |
| observability | Direct @sentry/vue usage | @solidprofessorhub/observability (includes PII scrubbing) |
| deprecation | useAuth/useHttp from shared-components | Standalone @solidprofessorhub/auth and /http packages |
Add a .shelfrc.json at repo root to customize behavior:
{
"ignore": [
"**/test/**",
"**/stories/**",
"**/*.spec.ts"
],
"tokenDrift": "warn",
"customTokenMap": {
"#2d833f": "primary-50"
},
"allowedFontAwesomeIcons": [
"graduation-cap",
"bookmark"
],
"framework": "nuxt"
}
{
"ignore": [
"**/__tests__/**",
"**/stories/**",
"**/*.spec.ts",
"**/*.test.ts",
"server/**"
],
"framework": "nuxt",
"tokenDrift": "warn",
"allowedFontAwesomeIcons": [
"graduation-cap",
"cloud-arrow-down",
"bookmark"
]
}
Nuxt note: With "framework": "nuxt", shelf won't flag useFetch() for SSR data fetching — that's intentional in Nuxt. It will still flag fetch() and axios for client-side mutations.
{
"ignore": [
"**/__tests__/**",
"**/stories/**",
"**/*.spec.ts",
"**/*.test.ts",
"**/mocks/**"
],
"framework": "vue",
"tokenDrift": "strict"
}
Vue SPA note: All fetch() and axios calls to internal APIs should use @solidprofessorhub/http for consistent auth token injection and 401 refresh handling.
| Option | Purpose |
|---|---|
ignore |
Glob patterns to skip (tests, stories, legacy code) |
tokenDrift |
"strict" | "warn" | "skip" — how to handle close-but-not-exact token matches |
customTokenMap |
Project-specific hex → token mappings (for projects with different token values) |
allowedFontAwesomeIcons |
Icons that aren't in BaseIcon's token set — don't flag these |
framework |
"nuxt" | "vue" — affects rules (e.g., Nuxt useFetch() is not flagged) |
sp-claude-skills/
├── shelf/
│ ├── SKILL.md # Main skill definition
│ └── report-template.html # HTML report template
└── solidprofessor-packages/
└── SKILL.md # Proactive catalog
When updating the package catalog in solidprofessor-packages, also update the detection rules in shelf. They reference the same packages.
Current versions documented in the skill:
| Package | Version | Check Latest |
|---|---|---|
| @solidprofessorhub/shared-components | 1.29.x | npm view @solidprofessorhub/shared-components version |
| @solidprofessorhub/auth | 2.0.x | npm view @solidprofessorhub/auth version |
| @solidprofessorhub/http | 1.0.x | npm view @solidprofessorhub/http version |
| @solidprofessorhub/types | 1.0.x | npm view @solidprofessorhub/types version |
| @solidprofessorhub/observability | 0.0.x | npm view @solidprofessorhub/observability version |
Shelf flags opportunities, not requirements. Some findings are intentional (external URL fetch, Nuxt useFetch for SSR). Use judgment — the report is a starting point, not a mandate.
This section is often the most valuable — it surfaces capabilities you might not know exist:
Some findings are intentional and don't need action:
| Finding | When It's Intentional | Fix |
|---|---|---|
fetch() flagged |
Nuxt useFetch() for SSR data, or fetching external URLs (transcripts, third-party APIs) |
Add "framework": "nuxt" to .shelfrc.json; external URLs are noted as "confirm: external?" |
| FontAwesome icon flagged | Icon isn't in BaseIcon's token set (most icons) | Add to allowedFontAwesomeIcons in .shelfrc.json, or expand BaseIcon's token map |
| Hex color flagged | Project uses different token values than shared-components | Add mapping to customTokenMap in .shelfrc.json |
Raw <button> in tests |
Test files shouldn't use shared components | Add "**/*.test.ts" and "**/__tests__/**" to ignore patterns |
| Local type definition | Type extends or differs from shared type intentionally | Review if you can import and extend vs. duplicate; shelf flags "overlaps" not "identical" |
| @sentry/vue direct usage | @solidprofessorhub/observability not installed yet | Shelf notes "consider installing" — not a bug, just an adoption opportunity |
If a finding seems wrong, it probably is. Add an ignore pattern or allowlist entry rather than making a change you're not confident about. Shelf is advisory — false positives are expected and easy to suppress.