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 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 (see
36
- [The quality bar](#the-quality-bar)). The bar was real: skills that scored 8.0
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
- git clone https://github.com/ericrisco/skills.git ~/rsc-skills
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
- Then, inside any project of yours:
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
- cd ~/my-project
58
- rsc # the wizard: describe what you want, it installs what fits
54
+ git clone https://github.com/ericrisco/skills.git ~/rsc-skills
55
+ cd ~/rsc-skills && npm install && npm link
59
56
  ```
60
57
 
61
- > Once published: `npx rsc` with no install step. Prefer no global link? Call it
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
- Hola 👋 ¿Qué quieres hacer?
75
- > una tienda web con base de datos, y llevar la contabilidad
76
-
77
- He preparado esto para ti:
78
- Tu tienda (rápida y lista para Google) → nextjs, design, seo-geo
79
- Guardar tus datos de forma fiable → postgresdb
80
- Cobrar y facturar → stripe, invoicing
81
- Llevar las cuentas → bookkeeping, finance-ops
82
- Publicarlo online → vercel
83
- ¿Lo monto? ( / no) >
84
-
85
- Listo. Abre tu editor y empieza a pedir cosas en tu idioma.
86
- 💡 Cuando una tarea necesite algo más, te lo propongo yo.
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 "quiero lanzar un saas" # recommend only, no install
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. Invoke any installed skill by
158
- name in your assistant; it fires on its own when a task matches.
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
- `init` · `harness` · `author-skill` · `suggest` · `sdd-init`
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
- `sdd` · `constitution` · `specify` · `clarify` · `plan` · `tasks` · `analyze` · `implement` · `verify` · `review` · `ship` · `debug` · `worktrees` · `parallel`
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
- `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`
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
- `pitch-deck` · `investor-materials` · `financial-model` · `fundraising` · `unit-economics` · `grants`
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
- `gdpr-privacy` · `terms-conditions` · `compliance` · `data-policy` · `ip-trademark`
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
- ### 🎬 Grow a channel (each with a `02-DOCS` feedback loop)
185
- - **YouTube** — `youtube-api` · `youtube-strategy` · `youtube-ideation` · `youtube-thumbnails` · `youtube-packaging` · `remotion-video` *(Remotion edits: transitions, Whisper captions, silence removal)*
186
- - **TikTok / Reels** — `tiktok-api` · `instagram-api` · `shortform-strategy` · `shortform-ideation` · `shortform-packaging` · `shortform-editing`
187
- - **LinkedIn** `linkedin-api` · `linkedin-strategy` · `linkedin-content` · `linkedin-carousels` · `linkedin-outreach`
188
- - **Medium** — `medium-writing` · `medium-publishing` · `medium-strategy`
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
- `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`
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
- ### 🤖 AI features & infra
197
- - **Build AI in** — `building-agents` · `rag` · `embeddings-search` · `prompt-engineering` · `llm-pipeline` · `agent-eval` · `chatbot` · `ai-media` · `replicate-images` · `structured-extraction` · `agent-safety` · `cost-tracking`
198
- - **Run AI on** `replicate` · `runpod` · `modal` · `huggingface` · `ollama` · `together-fireworks` · `fal`
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
- `typescript` · `python` · `java` · `csharp-dotnet` · `php` · `ruby` · `cpp` · `elixir` · `bash-scripting` · `sql` · `go` *(+ `fastapi` for async Python services)*
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
- `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`
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
- ### ☁️ Ship & operate
210
- - **Platforms** — `vercel` · `netlify` · `cloudflare` · `railway` · `render` · `fly-io` · `coolify` · `hetzner` · `digitalocean` · `aws-essentials` · `gcp-essentials`
211
- - **DevOps** `docker` · `github-actions` · `git-workflow` · `domains-dns` · `monitoring` · `email-deliverability` · `scaling` · `deployment`
212
- - **Quality & security** — `code-review` · `security-scan` · `secure-coding` · `testing-py` · `testing-web` · `testing-go` · `e2e-testing` · `accessibility` · `performance` · `error-handling` · `observability`
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
- `design` · `presentations` · `course-storytelling` · `course-builder` · `technical-writing` · `translation-l10n`
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
- `knowledge-ops` · `codebase-onboarding` · `research-ops` · `decision-records` · `continuous-learning` · `skill-scout` · `context-budget`
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
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.1",
2
+ "version": "0.1.2",
3
3
  "counts": {
4
4
  "skills": 231
5
5
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rsc-universal",
3
- "version": "0.1.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
+ }
@@ -1,21 +1,21 @@
1
1
  import { skillById } from './manifest.js';
2
2
 
3
3
  const OUTCOMES = {
4
- suggest: 'Un asistente que te va proponiendo lo que necesitas',
5
- harness: 'Un espacio de trabajo ordenado: conecta y documenta tu empresa',
6
- init: 'Arranque guiado de tu proyecto',
7
- nextjs: 'Tu web (rápida y lista para Google)',
8
- flutter: 'Tu app de móvil',
9
- fastapi: 'Tu API / backend en Python',
10
- go: 'Tu servicio backend en Go',
11
- postgresdb: 'Guardar tus datos de forma fiable',
12
- design: 'Que se vea bien y convierta',
13
- marketing: 'Textos que venden',
14
- presentations: 'Presentaciones con tu marca',
15
- 'course-storytelling': 'Enseñar de forma que se entienda',
16
- 'building-agents': 'Un agente de IA propio',
17
- 'secure-coding': 'Que sea seguro',
18
- deployment: 'Publicarlo online',
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
- async function wizard() {
33
- say('Hola 👋 ¿Qué quieres hacer?');
34
- const goal = await ask('> ');
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('No estoy seguro de qué necesitas. Prueba a describir tu proyecto con más detalle.');
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('\nHe preparado esto para ti:');
56
+ say('\nI recommend installing:');
41
57
  for (const o of toOutcomes(ids)) say(` • ${o.label}`);
42
- const ok = yes(await ask('\n¿Lo monto? (sí / no) > '));
43
- if (!ok) {
44
- say('Sin problema. Cuando quieras: npx rsc');
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
- await applyInstall({ skillIds: [...new Set(['suggest', ...ids])], target });
49
- say('\n✅ Listo. Abre tu editor y empieza a pedir cosas en tu idioma.');
50
- say(' 💡 Para añadir más cuando lo necesites, vuelve a escribir: npx rsc');
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(`✅ Instalado: ${argv.slice(1).join(', ')}`);
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(`✅ Perfil '${profile}' instalado en ${target} (${ids.length} skills)`);
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('(sin recomendaciones)');
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') || '(nada instalado)');
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 actualizado: .rsc/skill-registry.md (${registry.counts.skills} skills)`);
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('Usa: npx rsc registry refresh | registry status');
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 ? 'Se borraría:\n' : 'Borrado:\n') + (removed.join('\n') || '(nada)'));
175
+ return void say((dry ? 'Would remove:\n' : 'Removed:\n') + (removed.join('\n') || '(nothing)'));
98
176
  }
99
177
  default:
100
- say(`rsc: comando desconocido '${cmd}'.`);
101
- say('Usa: npx rsc | add <id...> | install --profile <p> | consult "<texto>" | list | registry refresh | doctor | uninstall <id>');
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