rsc-universal 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -83
- package/manifest.json +1 -1
- package/package.json +2 -1
- package/scripts/lib/domains.js +30 -0
- package/scripts/lib/recommend.js +15 -15
- package/scripts/lib/ui.js +29 -0
- package/scripts/rsc.js +102 -24
package/README.md
CHANGED
|
@@ -32,9 +32,9 @@ one is the opposite bet:
|
|
|
32
32
|
invoicing, hiring, GDPR, pitch decks, SEO, a YouTube/TikTok/LinkedIn presence —
|
|
33
33
|
each wired to a `02-DOCS/` knowledge loop that learns from your own results.
|
|
34
34
|
- **Honestly good.** Every skill was built by a research → spec → implement →
|
|
35
|
-
*adversarial review* pipeline and had to clear an objective rubric
|
|
36
|
-
|
|
37
|
-
were sent back and fixed, not waved through.
|
|
35
|
+
*adversarial review* pipeline and had to clear an objective rubric
|
|
36
|
+
(`scripts/skill-rubric.md`, written *before* any skill existed). The bar was
|
|
37
|
+
real: skills that scored 8.0 were sent back and fixed, not waved through.
|
|
38
38
|
|
|
39
39
|
`skills/<name>/` is the single source of truth. There are no bundles to argue
|
|
40
40
|
over: you start with a tiny floor and grow one piece at a time.
|
|
@@ -43,25 +43,19 @@ over: you start with a tiny floor and grow one piece at a time.
|
|
|
43
43
|
|
|
44
44
|
## Install
|
|
45
45
|
|
|
46
|
-
The catalog ships as the `rsc-universal` CLI. Until it's on npm, install from
|
|
47
|
-
source (one minute, once):
|
|
48
|
-
|
|
49
46
|
```bash
|
|
50
|
-
|
|
51
|
-
cd ~/rsc-skills && npm install && npm link # puts `rsc` on your PATH
|
|
47
|
+
npx rsc # no install step — runs the latest published catalog
|
|
52
48
|
```
|
|
53
49
|
|
|
54
|
-
|
|
50
|
+
Run it inside any project and describe what you want. Working on the catalog
|
|
51
|
+
itself? Clone and link:
|
|
55
52
|
|
|
56
53
|
```bash
|
|
57
|
-
|
|
58
|
-
rsc
|
|
54
|
+
git clone https://github.com/ericrisco/skills.git ~/rsc-skills
|
|
55
|
+
cd ~/rsc-skills && npm install && npm link
|
|
59
56
|
```
|
|
60
57
|
|
|
61
|
-
|
|
62
|
-
> directly: `node ~/rsc-skills/scripts/rsc.js <args>`.
|
|
63
|
-
|
|
64
|
-
The first run installs the **floor** — `rsc-suggest` (always-on detector) +
|
|
58
|
+
The first run installs the **floor** — `orient` + `rsc-suggest` (always-on) +
|
|
65
59
|
`harness` + `init` — and, in Claude Code, wires a `SessionStart` hook so your
|
|
66
60
|
assistant proposes new skills on its own from then on.
|
|
67
61
|
|
|
@@ -71,19 +65,19 @@ assistant proposes new skills on its own from then on.
|
|
|
71
65
|
|
|
72
66
|
```
|
|
73
67
|
$ rsc
|
|
74
|
-
|
|
75
|
-
>
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
•
|
|
79
|
-
•
|
|
80
|
-
•
|
|
81
|
-
•
|
|
82
|
-
•
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
✅
|
|
86
|
-
💡
|
|
68
|
+
Hi 👋 What do you want to do?
|
|
69
|
+
> a web store with a database, and keep the books
|
|
70
|
+
|
|
71
|
+
Here's what I've lined up for you:
|
|
72
|
+
• Your store (fast, ready for Google) → nextjs, design, seo-geo
|
|
73
|
+
• Store your data reliably → postgresdb
|
|
74
|
+
• Charge customers and invoice them → stripe, invoicing
|
|
75
|
+
• Keep the accounts → bookkeeping, finance-ops
|
|
76
|
+
• Put it online → vercel
|
|
77
|
+
Shall I set it up? (yes / no) > yes
|
|
78
|
+
|
|
79
|
+
✅ Done. Open your editor and start asking for things in your own words.
|
|
80
|
+
💡 When a task needs something more, I'll offer it.
|
|
87
81
|
```
|
|
88
82
|
|
|
89
83
|
It detects your stack from the repo, maps your words to outcomes, installs the
|
|
@@ -97,11 +91,11 @@ matching skills, then suggests what usually comes next.
|
|
|
97
91
|
rsc # plain-language wizard (recommended)
|
|
98
92
|
rsc add fastapi postgresdb # install specific skills, by name
|
|
99
93
|
rsc add youtube-api remotion-video # …grow a channel, edit with Remotion
|
|
100
|
-
rsc install --profile minimal # the floor: suggest + harness + init
|
|
94
|
+
rsc install --profile minimal # the floor: orient + suggest + harness + init
|
|
101
95
|
rsc install --profile core # floor + the full SDD workflow
|
|
102
96
|
rsc install --profile full # everything (all 231)
|
|
103
97
|
rsc install --profile full --without go
|
|
104
|
-
rsc consult "
|
|
98
|
+
rsc consult "I want to launch a SaaS" # recommend only, no install
|
|
105
99
|
rsc registry refresh # write .rsc/skill-registry.{json,md}
|
|
106
100
|
rsc list # what rsc has installed
|
|
107
101
|
rsc doctor # health check (state, hook, counts)
|
|
@@ -128,94 +122,94 @@ just asks in plain language.
|
|
|
128
122
|
|
|
129
123
|
---
|
|
130
124
|
|
|
131
|
-
## The quality bar
|
|
132
|
-
|
|
133
|
-
This catalog was built to a test that was **written before any skill existed**
|
|
134
|
-
(`scripts/skill-rubric.md`). Each finished skill was scored 0-10 by an
|
|
135
|
-
independent adversarial reviewer across seven weighted dimensions — with
|
|
136
|
-
**freshness & grounding the heaviest (0.25)**: every load-bearing claim had to be
|
|
137
|
-
*current* (2025-2026 versions/APIs) and cited to a dated source. The ship gate
|
|
138
|
-
was **≥ 8.5**; anything below was sent back through a fix loop, not rounded up.
|
|
139
|
-
|
|
140
|
-
| | |
|
|
141
|
-
|---|---|
|
|
142
|
-
| **Skills** | 231 (30 core + 201 added) |
|
|
143
|
-
| **Domains** | 21 |
|
|
144
|
-
| **Median family score** | **~9.1 / 10** |
|
|
145
|
-
| **Below the 8.5 gate** | 0 (three were flagged, then remediated to 9.0-9.3) |
|
|
146
|
-
| **Deterministic gates** | eval-lint ✓ · frontmatter+`recommends` validate ✓ · 50/50 unit tests ✓ · every description ≤ 1024 chars ✓ |
|
|
147
|
-
|
|
148
|
-
Each skill is **hybrid**: a focused `SKILL.md` (120-400 lines), deep-dive
|
|
149
|
-
`references/`, an `evals/cases.yaml` (≥5 trigger / ≥4 near-miss / ≥1 capability
|
|
150
|
-
scenario), and — for anything with a checkable artifact — an executable
|
|
151
|
-
`scripts/verify.sh`.
|
|
152
|
-
|
|
153
|
-
---
|
|
154
|
-
|
|
155
125
|
## The catalog
|
|
156
126
|
|
|
157
|
-
231 skills, grouped by what you're trying to do.
|
|
158
|
-
|
|
127
|
+
231 skills, grouped by what you're trying to do. Click any skill to read its
|
|
128
|
+
`SKILL.md`. It fires on its own when a task matches.
|
|
159
129
|
|
|
160
130
|
### 🧭 Core & control plane
|
|
161
131
|
The front door and the workspace brain.
|
|
162
|
-
|
|
132
|
+
|
|
133
|
+
[init](skills/init/) · [harness](skills/harness/) · [orient](skills/orient/) · [suggest](skills/suggest/) · [author-skill](skills/author-skill/) · [sdd-init](skills/sdd-init/)
|
|
163
134
|
|
|
164
135
|
> **harness** is the Karpathy *chaos→knowledge* engine — a `01-TOOLS/` layer (one
|
|
165
136
|
> folder per provider, each with a working `test_connection`) and a `02-DOCS/`
|
|
166
|
-
> self-improving wiki. It governs software *or* a whole company.
|
|
137
|
+
> self-improving wiki. It governs software *or* a whole company. **orient** is the
|
|
138
|
+
> always-on compass that keeps a non-technical human oriented after every step.
|
|
167
139
|
|
|
168
140
|
### 📐 Spec-Driven Development
|
|
169
|
-
Take a fuzzy intent to a shipped, verified change — phase by phase. `rsc install --profile core`.
|
|
170
|
-
|
|
141
|
+
Take a fuzzy intent to a shipped, verified change — phase by phase. `npx rsc install --profile core`.
|
|
142
|
+
|
|
143
|
+
[sdd](skills/sdd/) · [constitution](skills/constitution/) · [specify](skills/specify/) · [clarify](skills/clarify/) · [plan](skills/plan/) · [tasks](skills/tasks/) · [analyze](skills/analyze/) · [implement](skills/implement/) · [verify](skills/verify/) · [review](skills/review/) · [ship](skills/ship/) · [debug](skills/debug/) · [worktrees](skills/worktrees/) · [parallel](skills/parallel/)
|
|
171
144
|
|
|
172
145
|
### 💼 Run a business
|
|
173
|
-
|
|
146
|
+
|
|
147
|
+
[finance-ops](skills/finance-ops/) · [invoicing](skills/invoicing/) · [bookkeeping](skills/bookkeeping/) · [pricing](skills/pricing/) · [sales-pipeline](skills/sales-pipeline/) · [lead-gen](skills/lead-gen/) · [cold-outreach](skills/cold-outreach/) · [proposals](skills/proposals/) · [contracts](skills/contracts/) · [customer-support](skills/customer-support/) · [client-onboarding](skills/client-onboarding/) · [retention](skills/retention/) · [hiring](skills/hiring/) · [people-ops](skills/people-ops/) · [inventory](skills/inventory/) · [logistics-ops](skills/logistics-ops/) · [procurement](skills/procurement/) · [meeting-notes](skills/meeting-notes/) · [sop-builder](skills/sop-builder/) · [project-ops](skills/project-ops/)
|
|
174
148
|
|
|
175
149
|
### 💸 Raise & model money
|
|
176
|
-
|
|
150
|
+
|
|
151
|
+
[pitch-deck](skills/pitch-deck/) · [investor-materials](skills/investor-materials/) · [financial-model](skills/financial-model/) · [fundraising](skills/fundraising/) · [unit-economics](skills/unit-economics/) · [grants](skills/grants/)
|
|
177
152
|
|
|
178
153
|
### ⚖️ Legal, privacy & compliance
|
|
179
|
-
|
|
154
|
+
|
|
155
|
+
[gdpr-privacy](skills/gdpr-privacy/) · [terms-conditions](skills/terms-conditions/) · [compliance](skills/compliance/) · [data-policy](skills/data-policy/) · [ip-trademark](skills/ip-trademark/)
|
|
180
156
|
|
|
181
157
|
### 📣 Market & brand
|
|
182
|
-
`seo-geo` · `content-engine` · `social-publisher` · `brand-voice` · `brand-identity` · `newsletter` · `landing-copy` · `ads` · `article-writing` · `case-studies` · `video-shorts` · `podcast` · `market-research` · `competitor-watch` · `press-kit` · `community` · `webinar` · `review-management` · `marketing`
|
|
183
158
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
159
|
+
[marketing](skills/marketing/) · [seo-geo](skills/seo-geo/) · [content-engine](skills/content-engine/) · [social-publisher](skills/social-publisher/) · [brand-voice](skills/brand-voice/) · [brand-identity](skills/brand-identity/) · [newsletter](skills/newsletter/) · [landing-copy](skills/landing-copy/) · [ads](skills/ads/) · [article-writing](skills/article-writing/) · [case-studies](skills/case-studies/) · [video-shorts](skills/video-shorts/) · [podcast](skills/podcast/) · [market-research](skills/market-research/) · [competitor-watch](skills/competitor-watch/) · [press-kit](skills/press-kit/) · [community](skills/community/) · [webinar](skills/webinar/) · [review-management](skills/review-management/)
|
|
160
|
+
|
|
161
|
+
### 🎬 Grow a channel
|
|
162
|
+
Each with a `02-DOCS` feedback loop that learns from your own results. `remotion-video` edits programmatically — transitions, Whisper captions, silence removal.
|
|
163
|
+
|
|
164
|
+
[youtube-api](skills/youtube-api/) · [youtube-strategy](skills/youtube-strategy/) · [youtube-ideation](skills/youtube-ideation/) · [youtube-thumbnails](skills/youtube-thumbnails/) · [youtube-packaging](skills/youtube-packaging/) · [remotion-video](skills/remotion-video/) · [tiktok-api](skills/tiktok-api/) · [instagram-api](skills/instagram-api/) · [shortform-strategy](skills/shortform-strategy/) · [shortform-ideation](skills/shortform-ideation/) · [shortform-packaging](skills/shortform-packaging/) · [shortform-editing](skills/shortform-editing/) · [linkedin-api](skills/linkedin-api/) · [linkedin-strategy](skills/linkedin-strategy/) · [linkedin-content](skills/linkedin-content/) · [linkedin-carousels](skills/linkedin-carousels/) · [linkedin-outreach](skills/linkedin-outreach/) · [medium-writing](skills/medium-writing/) · [medium-publishing](skills/medium-publishing/) · [medium-strategy](skills/medium-strategy/)
|
|
189
165
|
|
|
190
166
|
### 🔌 Connect & automate
|
|
191
|
-
|
|
167
|
+
|
|
168
|
+
[stripe](skills/stripe/) · [email-connector](skills/email-connector/) · [google-workspace](skills/google-workspace/) · [notion-connector](skills/notion-connector/) · [whatsapp-telegram](skills/whatsapp-telegram/) · [automation-flows](skills/automation-flows/) · [api-connector-builder](skills/api-connector-builder/) · [webhooks](skills/webhooks/) · [data-scraper](skills/data-scraper/) · [spreadsheet-ops](skills/spreadsheet-ops/) · [calendar-scheduling](skills/calendar-scheduling/) · [document-processing](skills/document-processing/) · [e-signature](skills/e-signature/)
|
|
192
169
|
|
|
193
170
|
### 📊 Data & analytics
|
|
194
|
-
`analytics` · `dashboard` · `kpi-framework` · `reporting` · `ab-testing` · `forecasting` · `data-cleaning` · `business-intelligence`
|
|
195
171
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
172
|
+
[analytics](skills/analytics/) · [dashboard](skills/dashboard/) · [kpi-framework](skills/kpi-framework/) · [reporting](skills/reporting/) · [ab-testing](skills/ab-testing/) · [forecasting](skills/forecasting/) · [data-cleaning](skills/data-cleaning/) · [business-intelligence](skills/business-intelligence/)
|
|
173
|
+
|
|
174
|
+
### 🤖 AI — build it in
|
|
175
|
+
|
|
176
|
+
[building-agents](skills/building-agents/) · [rag](skills/rag/) · [embeddings-search](skills/embeddings-search/) · [prompt-engineering](skills/prompt-engineering/) · [llm-pipeline](skills/llm-pipeline/) · [agent-eval](skills/agent-eval/) · [chatbot](skills/chatbot/) · [ai-media](skills/ai-media/) · [replicate-images](skills/replicate-images/) · [structured-extraction](skills/structured-extraction/) · [agent-safety](skills/agent-safety/) · [cost-tracking](skills/cost-tracking/)
|
|
177
|
+
|
|
178
|
+
### 🛰️ AI — run it on
|
|
179
|
+
|
|
180
|
+
[replicate](skills/replicate/) · [runpod](skills/runpod/) · [modal](skills/modal/) · [huggingface](skills/huggingface/) · [ollama](skills/ollama/) · [together-fireworks](skills/together-fireworks/) · [fal](skills/fal/)
|
|
199
181
|
|
|
200
182
|
### 🗣️ Languages
|
|
201
|
-
|
|
183
|
+
|
|
184
|
+
[typescript](skills/typescript/) · [python](skills/python/) · [java](skills/java/) · [csharp-dotnet](skills/csharp-dotnet/) · [php](skills/php/) · [ruby](skills/ruby/) · [cpp](skills/cpp/) · [elixir](skills/elixir/) · [bash-scripting](skills/bash-scripting/) · [sql](skills/sql/) · [go](skills/go/)
|
|
202
185
|
|
|
203
186
|
### 🏗️ Frameworks & app stacks
|
|
204
|
-
|
|
187
|
+
|
|
188
|
+
[fastapi](skills/fastapi/) · [nextjs](skills/nextjs/) · [react](skills/react/) · [react-native](skills/react-native/) · [vue-nuxt](skills/vue-nuxt/) · [angular](skills/angular/) · [svelte](skills/svelte/) · [astro](skills/astro/) · [solid-js](skills/solid-js/) · [htmx](skills/htmx/) · [nodejs](skills/nodejs/) · [nestjs](skills/nestjs/) · [django](skills/django/) · [laravel](skills/laravel/) · [rails](skills/rails/) · [spring-boot](skills/spring-boot/) · [phoenix](skills/phoenix/) · [flutter](skills/flutter/) · [swift-ios](skills/swift-ios/) · [kotlin-android](skills/kotlin-android/) · [compose-multiplatform](skills/compose-multiplatform/) · [expo](skills/expo/) · [tauri](skills/tauri/) · [electron](skills/electron/) · [rust](skills/rust/) · [wordpress](skills/wordpress/) · [shopify](skills/shopify/) · [no-code-app](skills/no-code-app/) · [chrome-extension](skills/chrome-extension/) · [api-design](skills/api-design/)
|
|
205
189
|
|
|
206
190
|
### 🗄️ Databases & data layer
|
|
207
|
-
`postgresdb` · `mysql` · `mongodb` · `redis` · `supabase` · `neon` · `planetscale` · `sqlite-turso` · `prisma-orm` · `drizzle-orm` · `firebase` · `dynamodb` · `vector-db` · `clickhouse-analytics` · `duckdb` · `db-migrations` · `backups`
|
|
208
191
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
192
|
+
[postgresdb](skills/postgresdb/) · [mysql](skills/mysql/) · [mongodb](skills/mongodb/) · [redis](skills/redis/) · [supabase](skills/supabase/) · [neon](skills/neon/) · [planetscale](skills/planetscale/) · [sqlite-turso](skills/sqlite-turso/) · [prisma-orm](skills/prisma-orm/) · [drizzle-orm](skills/drizzle-orm/) · [firebase](skills/firebase/) · [dynamodb](skills/dynamodb/) · [vector-db](skills/vector-db/) · [clickhouse-analytics](skills/clickhouse-analytics/) · [duckdb](skills/duckdb/) · [db-migrations](skills/db-migrations/) · [backups](skills/backups/)
|
|
193
|
+
|
|
194
|
+
### ☁️ Ship & operate — platforms
|
|
195
|
+
|
|
196
|
+
[vercel](skills/vercel/) · [netlify](skills/netlify/) · [cloudflare](skills/cloudflare/) · [railway](skills/railway/) · [render](skills/render/) · [fly-io](skills/fly-io/) · [coolify](skills/coolify/) · [hetzner](skills/hetzner/) · [digitalocean](skills/digitalocean/) · [aws-essentials](skills/aws-essentials/) · [gcp-essentials](skills/gcp-essentials/)
|
|
197
|
+
|
|
198
|
+
### 🛠️ Ship & operate — devops
|
|
199
|
+
|
|
200
|
+
[docker](skills/docker/) · [github-actions](skills/github-actions/) · [git-workflow](skills/git-workflow/) · [domains-dns](skills/domains-dns/) · [monitoring](skills/monitoring/) · [email-deliverability](skills/email-deliverability/) · [scaling](skills/scaling/) · [deployment](skills/deployment/)
|
|
201
|
+
|
|
202
|
+
### 🔒 Ship & operate — quality & security
|
|
203
|
+
|
|
204
|
+
[code-review](skills/code-review/) · [security-scan](skills/security-scan/) · [secure-coding](skills/secure-coding/) · [testing-py](skills/testing-py/) · [testing-web](skills/testing-web/) · [testing-go](skills/testing-go/) · [e2e-testing](skills/e2e-testing/) · [accessibility](skills/accessibility/) · [performance](skills/performance/) · [error-handling](skills/error-handling/) · [observability](skills/observability/)
|
|
213
205
|
|
|
214
206
|
### 🎨 Design & content craft
|
|
215
|
-
|
|
207
|
+
|
|
208
|
+
[design](skills/design/) · [presentations](skills/presentations/) · [course-storytelling](skills/course-storytelling/) · [course-builder](skills/course-builder/) · [technical-writing](skills/technical-writing/) · [translation-l10n](skills/translation-l10n/)
|
|
216
209
|
|
|
217
210
|
### 🧠 Knowledge & meta
|
|
218
|
-
|
|
211
|
+
|
|
212
|
+
[knowledge-ops](skills/knowledge-ops/) · [codebase-onboarding](skills/codebase-onboarding/) · [research-ops](skills/research-ops/) · [decision-records](skills/decision-records/) · [continuous-learning](skills/continuous-learning/) · [skill-scout](skills/skill-scout/) · [context-budget](skills/context-budget/)
|
|
219
213
|
|
|
220
214
|
---
|
|
221
215
|
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rsc-universal",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Eric Risco's agent-skills catalog as a granular, self-recommending CLI installer.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"validate": "node scripts/build-manifest.js --validate",
|
|
17
17
|
"test": "node --test",
|
|
18
18
|
"coverage": "c8 --reporter=text node --test",
|
|
19
|
+
"version": "npm run manifest && git add manifest.json",
|
|
19
20
|
"prepublishOnly": "npm run manifest && npm run validate"
|
|
20
21
|
},
|
|
21
22
|
"dependencies": {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// domains.js — the catalog grouped by what the user is trying to do.
|
|
2
|
+
// Single source for the CLI's manual picker. Every skill id in the manifest
|
|
3
|
+
// MUST appear in exactly one domain (enforced by tests/domains.test.js) so the
|
|
4
|
+
// catalog grows deliberately, never silently.
|
|
5
|
+
|
|
6
|
+
export const DOMAINS = [
|
|
7
|
+
{ title: 'Core & control plane', ids: ['init', 'harness', 'orient', 'suggest', 'author-skill', 'sdd-init'] },
|
|
8
|
+
{ title: 'Spec-Driven Development', ids: ['sdd', 'constitution', 'specify', 'clarify', 'plan', 'tasks', 'analyze', 'implement', 'verify', 'review', 'ship', 'debug', 'worktrees', 'parallel'] },
|
|
9
|
+
{ title: 'Run a business', ids: ['finance-ops', 'invoicing', 'bookkeeping', 'pricing', 'sales-pipeline', 'lead-gen', 'cold-outreach', 'proposals', 'contracts', 'customer-support', 'client-onboarding', 'retention', 'hiring', 'people-ops', 'inventory', 'logistics-ops', 'procurement', 'meeting-notes', 'sop-builder', 'project-ops'] },
|
|
10
|
+
{ title: 'Raise & model money', ids: ['pitch-deck', 'investor-materials', 'financial-model', 'fundraising', 'unit-economics', 'grants'] },
|
|
11
|
+
{ title: 'Legal, privacy & compliance', ids: ['gdpr-privacy', 'terms-conditions', 'compliance', 'data-policy', 'ip-trademark'] },
|
|
12
|
+
{ title: 'Market & brand', ids: ['marketing', 'seo-geo', 'content-engine', 'social-publisher', 'brand-voice', 'brand-identity', 'newsletter', 'landing-copy', 'ads', 'article-writing', 'case-studies', 'video-shorts', 'podcast', 'market-research', 'competitor-watch', 'press-kit', 'community', 'webinar', 'review-management'] },
|
|
13
|
+
{ title: 'Grow a channel (YouTube / TikTok / Reels / LinkedIn / Medium)', ids: ['youtube-api', 'youtube-strategy', 'youtube-ideation', 'youtube-thumbnails', 'youtube-packaging', 'remotion-video', 'tiktok-api', 'instagram-api', 'shortform-strategy', 'shortform-ideation', 'shortform-packaging', 'shortform-editing', 'linkedin-api', 'linkedin-strategy', 'linkedin-content', 'linkedin-carousels', 'linkedin-outreach', 'medium-writing', 'medium-publishing', 'medium-strategy'] },
|
|
14
|
+
{ title: 'Connect & automate', ids: ['stripe', 'email-connector', 'google-workspace', 'notion-connector', 'whatsapp-telegram', 'automation-flows', 'api-connector-builder', 'webhooks', 'data-scraper', 'spreadsheet-ops', 'calendar-scheduling', 'document-processing', 'e-signature'] },
|
|
15
|
+
{ title: 'Data & analytics', ids: ['analytics', 'dashboard', 'kpi-framework', 'reporting', 'ab-testing', 'forecasting', 'data-cleaning', 'business-intelligence'] },
|
|
16
|
+
{ title: 'AI — build it in', ids: ['building-agents', 'rag', 'embeddings-search', 'prompt-engineering', 'llm-pipeline', 'agent-eval', 'chatbot', 'ai-media', 'replicate-images', 'structured-extraction', 'agent-safety', 'cost-tracking'] },
|
|
17
|
+
{ title: 'AI — run it on', ids: ['replicate', 'runpod', 'modal', 'huggingface', 'ollama', 'together-fireworks', 'fal'] },
|
|
18
|
+
{ title: 'Languages', ids: ['typescript', 'python', 'java', 'csharp-dotnet', 'php', 'ruby', 'cpp', 'elixir', 'bash-scripting', 'sql', 'go'] },
|
|
19
|
+
{ title: 'Frameworks & app stacks', ids: ['fastapi', 'nextjs', 'react', 'react-native', 'vue-nuxt', 'angular', 'svelte', 'astro', 'solid-js', 'htmx', 'nodejs', 'nestjs', 'django', 'laravel', 'rails', 'spring-boot', 'phoenix', 'flutter', 'swift-ios', 'kotlin-android', 'compose-multiplatform', 'expo', 'tauri', 'electron', 'rust', 'wordpress', 'shopify', 'no-code-app', 'chrome-extension', 'api-design'] },
|
|
20
|
+
{ title: 'Databases & data layer', ids: ['postgresdb', 'mysql', 'mongodb', 'redis', 'supabase', 'neon', 'planetscale', 'sqlite-turso', 'prisma-orm', 'drizzle-orm', 'firebase', 'dynamodb', 'vector-db', 'clickhouse-analytics', 'duckdb', 'db-migrations', 'backups'] },
|
|
21
|
+
{ title: 'Ship & operate — platforms', ids: ['vercel', 'netlify', 'cloudflare', 'railway', 'render', 'fly-io', 'coolify', 'hetzner', 'digitalocean', 'aws-essentials', 'gcp-essentials'] },
|
|
22
|
+
{ title: 'Ship & operate — devops', ids: ['docker', 'github-actions', 'git-workflow', 'domains-dns', 'monitoring', 'email-deliverability', 'scaling', 'deployment'] },
|
|
23
|
+
{ title: 'Ship & operate — quality & security', ids: ['code-review', 'security-scan', 'secure-coding', 'testing-py', 'testing-web', 'testing-go', 'e2e-testing', 'accessibility', 'performance', 'error-handling', 'observability'] },
|
|
24
|
+
{ title: 'Design & content craft', ids: ['design', 'presentations', 'course-storytelling', 'course-builder', 'technical-writing', 'translation-l10n'] },
|
|
25
|
+
{ title: 'Knowledge & meta', ids: ['knowledge-ops', 'codebase-onboarding', 'research-ops', 'decision-records', 'continuous-learning', 'skill-scout', 'context-budget'] },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
export function allDomainIds() {
|
|
29
|
+
return DOMAINS.flatMap((d) => d.ids);
|
|
30
|
+
}
|
package/scripts/lib/recommend.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { skillById } from './manifest.js';
|
|
2
2
|
|
|
3
3
|
const OUTCOMES = {
|
|
4
|
-
suggest: '
|
|
5
|
-
harness: '
|
|
6
|
-
init: '
|
|
7
|
-
nextjs: '
|
|
8
|
-
flutter: '
|
|
9
|
-
fastapi: '
|
|
10
|
-
go: '
|
|
11
|
-
postgresdb: '
|
|
12
|
-
design: '
|
|
13
|
-
marketing: '
|
|
14
|
-
presentations: '
|
|
15
|
-
'course-storytelling': '
|
|
16
|
-
'building-agents': '
|
|
17
|
-
'secure-coding': '
|
|
18
|
-
deployment: '
|
|
4
|
+
suggest: 'An assistant that proposes what you need as you go',
|
|
5
|
+
harness: 'A tidy workspace: connect and document your company',
|
|
6
|
+
init: 'Guided project bootstrap',
|
|
7
|
+
nextjs: 'Your website (fast, ready for Google)',
|
|
8
|
+
flutter: 'Your mobile app',
|
|
9
|
+
fastapi: 'Your API / Python backend',
|
|
10
|
+
go: 'Your Go backend service',
|
|
11
|
+
postgresdb: 'Store your data reliably',
|
|
12
|
+
design: 'Make it look good and convert',
|
|
13
|
+
marketing: 'Copy that sells',
|
|
14
|
+
presentations: 'On-brand presentations',
|
|
15
|
+
'course-storytelling': 'Teach so it actually lands',
|
|
16
|
+
'building-agents': 'Your own AI agent',
|
|
17
|
+
'secure-coding': 'Make it secure',
|
|
18
|
+
deployment: 'Put it online',
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
export function hasOutcome(id) {
|
package/scripts/lib/ui.js
CHANGED
|
@@ -15,3 +15,32 @@ export function say(...lines) {
|
|
|
15
15
|
export function yes(s) {
|
|
16
16
|
return /^(s|si|sí|y|yes|ok|vale|dale)/i.test(s.trim());
|
|
17
17
|
}
|
|
18
|
+
|
|
19
|
+
// Numbered single-choice menu. options: [{ key, label }]. Accepts the number or
|
|
20
|
+
// the key typed verbatim. Returns the chosen key, or null if unrecognized.
|
|
21
|
+
export async function select(question, options) {
|
|
22
|
+
say(question);
|
|
23
|
+
options.forEach((o, i) => say(` ${i + 1}) ${o.label}`));
|
|
24
|
+
const a = (await ask('> ')).toLowerCase();
|
|
25
|
+
const n = parseInt(a, 10);
|
|
26
|
+
if (n >= 1 && n <= options.length) return options[n - 1].key;
|
|
27
|
+
const byKey = options.find((o) => o.key.toLowerCase() === a);
|
|
28
|
+
return byKey ? byKey.key : null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Numbered multi-select. items: array of strings. Accepts comma-separated
|
|
32
|
+
// numbers (e.g. "1,3,4"), "todo"/"all", or empty for none. Returns the subset.
|
|
33
|
+
export async function pickFrom(title, items) {
|
|
34
|
+
say(`\n${title}`);
|
|
35
|
+
items.forEach((id, i) => say(` ${String(i + 1).padStart(2)}) ${id}`));
|
|
36
|
+
say(' Comma-separated numbers (e.g. 1,3,4), "all", or Enter for none.');
|
|
37
|
+
const a = (await ask('> ')).trim();
|
|
38
|
+
if (!a) return [];
|
|
39
|
+
if (/^(todo|todas|all)$/i.test(a)) return [...items];
|
|
40
|
+
const picked = a
|
|
41
|
+
.split(',')
|
|
42
|
+
.map((s) => parseInt(s.trim(), 10))
|
|
43
|
+
.filter((x) => x >= 1 && x <= items.length)
|
|
44
|
+
.map((x) => items[x - 1]);
|
|
45
|
+
return [...new Set(picked)];
|
|
46
|
+
}
|
package/scripts/rsc.js
CHANGED
|
@@ -6,8 +6,9 @@ import { rank } from './consult.js';
|
|
|
6
6
|
import { expandRecommends, toOutcomes, hasOutcome } from './lib/recommend.js';
|
|
7
7
|
import { applyInstall, listInstalled, uninstall } from './install-apply.js';
|
|
8
8
|
import { doctor } from './doctor.js';
|
|
9
|
-
import { ask, say, yes } from './lib/ui.js';
|
|
9
|
+
import { ask, say, yes, select, pickFrom } from './lib/ui.js';
|
|
10
10
|
import { refreshRegistry, registryStatus } from './lib/registry.js';
|
|
11
|
+
import { DOMAINS } from './lib/domains.js';
|
|
11
12
|
|
|
12
13
|
const argv = process.argv.slice(2);
|
|
13
14
|
const cmd = argv[0];
|
|
@@ -29,25 +30,102 @@ async function recommendIds(query, { labeledOnly = false } = {}) {
|
|
|
29
30
|
return out.slice(0, 6);
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
33
|
+
// Pick skills by browsing the domains, accumulating across rounds.
|
|
34
|
+
async function manualSelect() {
|
|
35
|
+
const chosen = new Set();
|
|
36
|
+
for (;;) {
|
|
37
|
+
const opts = DOMAINS.map((d, i) => ({ key: String(i), label: `${d.title} (${d.ids.length})` }));
|
|
38
|
+
opts.push({ key: 'done', label: chosen.size ? `✅ Finish & install (${chosen.size} chosen)` : 'Finish without choosing anything' });
|
|
39
|
+
const k = await select('\nWhich area do you want to install skills from?', opts);
|
|
40
|
+
if (k === 'done' || k === null) break;
|
|
41
|
+
const d = DOMAINS[parseInt(k, 10)];
|
|
42
|
+
(await pickFrom(`${d.title}:`, d.ids)).forEach((id) => chosen.add(id));
|
|
43
|
+
say(` → ${chosen.size} skills chosen so far.`);
|
|
44
|
+
}
|
|
45
|
+
return [...chosen];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Describe-your-project flow: rsc reads repo + words and proposes skills.
|
|
49
|
+
async function describeFlow() {
|
|
50
|
+
const goal = await ask('\nTell me in one sentence what you want to build or run:\n> ');
|
|
35
51
|
const ids = await recommendIds(goal, { labeledOnly: true });
|
|
36
52
|
if (!ids.length) {
|
|
37
|
-
say('
|
|
38
|
-
return;
|
|
53
|
+
say("I'm not sure. Try describing it in more detail, or pick by hand (option 3).");
|
|
54
|
+
return [];
|
|
39
55
|
}
|
|
40
|
-
say('\
|
|
56
|
+
say('\nI recommend installing:');
|
|
41
57
|
for (const o of toOutcomes(ids)) say(` • ${o.label}`);
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
58
|
+
return ids;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// After installing, remind the user how to actually start — per IDE — and that
|
|
62
|
+
// rsc keeps recommending skills as they work. The harness/SDD *init* runs INSIDE
|
|
63
|
+
// the assistant (with the user present), never blindly from this CLI.
|
|
64
|
+
function printNextSteps(target, ids) {
|
|
65
|
+
const hasHarness = ids.includes('harness');
|
|
66
|
+
const hasSdd = ids.includes('sdd') || ids.includes('sdd-init');
|
|
67
|
+
const openLine = {
|
|
68
|
+
claude: 'Open **Claude Code** in this project folder.',
|
|
69
|
+
cursor: 'Open **Cursor** in this project folder.',
|
|
70
|
+
codex: 'Open **Codex CLI** (it reads AGENTS.md) in this project folder.',
|
|
71
|
+
gemini: 'Open **Gemini CLI** in this project folder.',
|
|
72
|
+
}[target] || 'Open your assistant in this project folder.';
|
|
73
|
+
|
|
74
|
+
say('\n────────────────────────────────────────────────────────');
|
|
75
|
+
say('👉 When you start working (these steps happen in your assistant, not here):');
|
|
76
|
+
let n = 1;
|
|
77
|
+
say(` ${n++}. ${openLine}`);
|
|
78
|
+
if (hasHarness) {
|
|
79
|
+
say(` ${n++}. Set up the second brain — tell it:`);
|
|
80
|
+
say(' "set up the harness for this project"');
|
|
81
|
+
say(' → creates 01-TOOLS/ (connections) + 02-DOCS/ (wiki) + CLAUDE.md/AGENTS.md.');
|
|
82
|
+
}
|
|
83
|
+
if (hasSdd) {
|
|
84
|
+
say(` ${n++}. For a new feature, tell it:`);
|
|
85
|
+
say(' "sdd-init" then "I want <your idea>"');
|
|
86
|
+
say(' → walks you specify → plan → tasks → implement → verify → ship.');
|
|
87
|
+
}
|
|
88
|
+
say(` ${n++}. From there, work in your own words. orient + suggest stay always-on:`);
|
|
89
|
+
say(' they keep you oriented after each step and propose the missing skill (you confirm, it installs).');
|
|
90
|
+
say('\n Add something by hand anytime: npx rsc add <skill>');
|
|
91
|
+
say(' Browse the catalog / get picks: npx rsc consult "whatever you need"');
|
|
92
|
+
say('────────────────────────────────────────────────────────');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function wizard() {
|
|
96
|
+
const m = loadManifest();
|
|
97
|
+
say('👋 rsc — the skill catalog for your assistant (Claude Code · Cursor · Codex · Gemini).');
|
|
98
|
+
const choice = await select('\nWhat do you want to do?', [
|
|
99
|
+
{ key: 'base', label: 'Base install — the essentials (orient + suggest + harness + init)' },
|
|
100
|
+
{ key: 'sdd', label: 'Base + Spec-Driven Development — the specify → plan → implement → ship flow' },
|
|
101
|
+
{ key: 'manual', label: 'Pick skills by hand, by area' },
|
|
102
|
+
{ key: 'describe', label: 'Describe my project and let rsc choose' },
|
|
103
|
+
]);
|
|
104
|
+
|
|
105
|
+
let ids = [];
|
|
106
|
+
if (choice === 'base') ids = skillsForProfile(m, 'minimal');
|
|
107
|
+
else if (choice === 'sdd') ids = skillsForProfile(m, 'core');
|
|
108
|
+
else if (choice === 'manual') ids = await manualSelect();
|
|
109
|
+
else if (choice === 'describe') ids = await describeFlow();
|
|
110
|
+
else { say("Didn't catch that. Run again: npx rsc"); return; }
|
|
111
|
+
|
|
112
|
+
// The floor is always installed: the compass + the detector.
|
|
113
|
+
ids = [...new Set(['orient', 'suggest', ...ids])];
|
|
114
|
+
if (ids.length <= 2 && choice !== 'base') {
|
|
115
|
+
say('\nNo skills were chosen. Anytime: npx rsc');
|
|
45
116
|
return;
|
|
46
117
|
}
|
|
118
|
+
|
|
47
119
|
const target = detectTarget();
|
|
48
|
-
|
|
49
|
-
say('
|
|
50
|
-
|
|
120
|
+
say(`\nI'll install ${ids.length} skills into ${target}:`);
|
|
121
|
+
say(' ' + ids.join(', '));
|
|
122
|
+
if (!yes(await ask('\nInstall it? (yes / no) > '))) {
|
|
123
|
+
say('No problem. Anytime: npx rsc');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
await applyInstall({ skillIds: ids, target });
|
|
127
|
+
say(`\n✅ Installed ${ids.length} skills into ${target}.`);
|
|
128
|
+
printNextSteps(target, ids);
|
|
51
129
|
}
|
|
52
130
|
|
|
53
131
|
async function main() {
|
|
@@ -56,49 +134,49 @@ async function main() {
|
|
|
56
134
|
case undefined:
|
|
57
135
|
return wizard();
|
|
58
136
|
case 'add':
|
|
59
|
-
await applyInstall({ skillIds: [...new Set(['suggest', ...argv.slice(1)])], target });
|
|
60
|
-
return void say(`✅
|
|
137
|
+
await applyInstall({ skillIds: [...new Set(['orient', 'suggest', ...argv.slice(1)])], target });
|
|
138
|
+
return void say(`✅ Installed: ${argv.slice(1).join(', ')}`);
|
|
61
139
|
case 'install': {
|
|
62
140
|
const profile = flag('profile') || 'minimal';
|
|
63
141
|
const without = argv.filter((a, i) => argv[i - 1] === '--without');
|
|
64
142
|
let ids = skillsForProfile(loadManifest(), profile);
|
|
65
|
-
ids = [...new Set(['suggest', ...ids])].filter((id) => !without.includes(id));
|
|
143
|
+
ids = [...new Set(['orient', 'suggest', ...ids])].filter((id) => !without.includes(id));
|
|
66
144
|
await applyInstall({ skillIds: ids, target });
|
|
67
|
-
return void say(`✅
|
|
145
|
+
return void say(`✅ Profile '${profile}' installed into ${target} (${ids.length} skills)`);
|
|
68
146
|
}
|
|
69
147
|
case 'consult': {
|
|
70
148
|
const ids = await recommendIds(argv.slice(1).join(' '));
|
|
71
|
-
if (!ids.length) return void say('(
|
|
149
|
+
if (!ids.length) return void say('(no recommendations)');
|
|
72
150
|
for (const o of toOutcomes(ids)) say(`${o.id}\t${o.label}`);
|
|
73
151
|
return;
|
|
74
152
|
}
|
|
75
153
|
case 'list':
|
|
76
|
-
return void say(listInstalled({ target }).join('\n') || '(
|
|
154
|
+
return void say(listInstalled({ target }).join('\n') || '(nothing installed)');
|
|
77
155
|
case 'doctor':
|
|
78
156
|
return void say(JSON.stringify(doctor({ target }), null, 2));
|
|
79
157
|
case 'registry': {
|
|
80
158
|
const sub = argv[1];
|
|
81
159
|
if (sub === 'refresh') {
|
|
82
160
|
const registry = refreshRegistry({ target });
|
|
83
|
-
say(`✅ Registry
|
|
161
|
+
say(`✅ Registry updated: .rsc/skill-registry.md (${registry.counts.skills} skills)`);
|
|
84
162
|
return;
|
|
85
163
|
}
|
|
86
164
|
if (sub === 'status') {
|
|
87
165
|
say(JSON.stringify(registryStatus(), null, 2));
|
|
88
166
|
return;
|
|
89
167
|
}
|
|
90
|
-
say('
|
|
168
|
+
say('Use: npx rsc registry refresh | registry status');
|
|
91
169
|
return;
|
|
92
170
|
}
|
|
93
171
|
case 'uninstall': {
|
|
94
172
|
const dry = argv.includes('--dry-run');
|
|
95
173
|
const ids = argv.slice(1).filter((a) => !a.startsWith('--'));
|
|
96
174
|
const removed = await uninstall({ skillIds: ids, target, dryRun: dry });
|
|
97
|
-
return void say((dry ? '
|
|
175
|
+
return void say((dry ? 'Would remove:\n' : 'Removed:\n') + (removed.join('\n') || '(nothing)'));
|
|
98
176
|
}
|
|
99
177
|
default:
|
|
100
|
-
say(`rsc:
|
|
101
|
-
say('
|
|
178
|
+
say(`rsc: unknown command '${cmd}'.`);
|
|
179
|
+
say('Use: npx rsc | add <id...> | install --profile <p> | consult "<text>" | list | registry refresh | doctor | uninstall <id>');
|
|
102
180
|
}
|
|
103
181
|
}
|
|
104
182
|
|