@ericrisco/rsc 3.1.4 → 3.3.1

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.
Files changed (98) hide show
  1. package/README.md +11 -7
  2. package/manifest.json +17 -68
  3. package/package.json +6 -1
  4. package/scripts/design-upstream.js +92 -0
  5. package/scripts/doctor.js +0 -24
  6. package/scripts/lib/default-skill-floor.js +5 -1
  7. package/scripts/lib/domains.js +2 -2
  8. package/scripts/lib/recommend.js +1 -3
  9. package/scripts/lib/retired-skills.js +7 -1
  10. package/skills/design/IMPECCABLE-LICENSE.txt +191 -0
  11. package/skills/design/SKILL.md +79 -328
  12. package/skills/design/THIRD_PARTY.md +26 -0
  13. package/skills/design/engine/LICENSE +21 -0
  14. package/skills/design/engine/RUN.md +515 -0
  15. package/skills/design/engine/UPSTREAM.json +4 -0
  16. package/skills/design/engine/assets/app.css +216 -0
  17. package/skills/design/engine/assets/base.css +105 -0
  18. package/skills/design/engine/assets/base.js +37 -0
  19. package/skills/design/engine/assets/charts.js +617 -0
  20. package/skills/design/engine/assets/scenes/stage.css +28 -0
  21. package/skills/design/engine/assets/scenes/stage.js +133 -0
  22. package/skills/design/engine/library/app.json +1327 -0
  23. package/skills/design/engine/library/directions.json +1078 -0
  24. package/skills/design/engine/library/heroes.json +1086 -0
  25. package/skills/design/engine/library/motions.json +92 -0
  26. package/skills/design/engine/library/palettes.json +1485 -0
  27. package/skills/design/engine/library/photos.json +7240 -0
  28. package/skills/design/engine/library/sections.json +4429 -0
  29. package/skills/design/engine/library/sites.json +8350 -0
  30. package/skills/design/engine/library/type.json +2024 -0
  31. package/skills/design/engine/references/app-screens.md +1199 -0
  32. package/skills/design/engine/references/colour.md +141 -0
  33. package/skills/design/engine/references/copy.md +177 -0
  34. package/skills/design/engine/references/critique.md +182 -0
  35. package/skills/design/engine/references/imagery.md +791 -0
  36. package/skills/design/engine/references/layout.md +292 -0
  37. package/skills/design/engine/references/motion.md +980 -0
  38. package/skills/design/engine/references/research.md +356 -0
  39. package/skills/design/engine/references/scenes.md +174 -0
  40. package/skills/design/engine/references/tells.md +115 -0
  41. package/skills/design/engine/references/type.md +170 -0
  42. package/skills/design/engine/scripts/assets.mjs +865 -0
  43. package/skills/design/engine/scripts/draw.mjs +584 -0
  44. package/skills/design/engine/scripts/inspect.mjs +303 -0
  45. package/skills/design/engine/scripts/lib/app-draw.mjs +203 -0
  46. package/skills/design/engine/scripts/lib/cdp.mjs +248 -0
  47. package/skills/design/engine/scripts/lib/probe.mjs +909 -0
  48. package/skills/design/engine/scripts/lib/rules.mjs +243 -0
  49. package/skills/design/engine/scripts/lint.mjs +119 -0
  50. package/skills/design/engine/scripts/scenes.mjs +124 -0
  51. package/skills/design/evals/cases.yaml +35 -46
  52. package/skills/design/references/design-md.md +49 -0
  53. package/skills/design/references/finish-review.md +46 -0
  54. package/skills/design/references/modes.md +51 -0
  55. package/skills/expo/SKILL.md +3 -4
  56. package/skills/marketing/references/landing-copy.md +2 -2
  57. package/skills/react/SKILL.md +2 -2
  58. package/skills/react-native/SKILL.md +3 -3
  59. package/skills/suggest/SKILL.md +12 -8
  60. package/skills/suggest/evals/cases.yaml +6 -0
  61. package/skills/swift-ios/SKILL.md +1 -1
  62. package/skills/ui-engineering/SKILL.md +3 -4
  63. package/skills/ui-engineering/evals/cases.yaml +2 -2
  64. package/skills/variant-explorer/SKILL.md +4 -4
  65. package/skills/variant-explorer/evals/cases.yaml +1 -1
  66. package/targets/clone-bootstrap.mjs +1 -1
  67. package/scripts/lib/design-identity.js +0 -117
  68. package/scripts/lib/starting-point.js +0 -314
  69. package/skills/design/evals/README.md +0 -53
  70. package/skills/design/references/ai-tells.md +0 -75
  71. package/skills/design/references/brand-grounding.md +0 -197
  72. package/skills/design/references/copywriting-frameworks.md +0 -138
  73. package/skills/design/references/design-systems.md +0 -49
  74. package/skills/design/references/inspiration-sources.md +0 -96
  75. package/skills/design/references/landing-anatomy-and-cro.md +0 -202
  76. package/skills/design/references/motion-and-interaction.md +0 -232
  77. package/skills/design/references/research-method.md +0 -154
  78. package/skills/design/references/signature-and-craft.md +0 -148
  79. package/skills/design/references/starting-point.md +0 -75
  80. package/skills/design/references/trends-2026.md +0 -80
  81. package/skills/design/references/visual-system.md +0 -237
  82. package/skills/design/scripts/verify.sh +0 -357
  83. package/skills/design-dna/PROMPT.md +0 -211
  84. package/skills/design-dna/SKILL.md +0 -162
  85. package/skills/design-dna/design-dna.schema.json +0 -230
  86. package/skills/design-dna/evals/README.md +0 -64
  87. package/skills/design-dna/evals/cases.yaml +0 -68
  88. package/skills/design-dna/references/method.md +0 -436
  89. package/skills/design-dna/scripts/emit.py +0 -164
  90. package/skills/design-dna/templates/PROMPT.md.tmpl +0 -42
  91. package/skills/design-dna/templates/SKILL.md.tmpl +0 -42
  92. package/skills/design-dna/templates/check.py.tmpl +0 -143
  93. package/skills/design-loop/SKILL.md +0 -160
  94. package/skills/design-loop/evals/README.md +0 -56
  95. package/skills/design-loop/evals/cases.yaml +0 -60
  96. package/skills/motion-craft/SKILL.md +0 -125
  97. package/skills/motion-craft/evals/cases.yaml +0 -38
  98. package/skills/motion-craft/scripts/verify.sh +0 -75
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  [![npm](https://img.shields.io/npm/v/@ericrisco/rsc?color=63d68a&labelColor=12161c&label=npm)](https://www.npmjs.com/package/@ericrisco/rsc)
10
10
  [![downloads](https://img.shields.io/npm/dm/@ericrisco/rsc?color=63d68a&labelColor=12161c&label=downloads)](https://www.npmjs.com/package/@ericrisco/rsc)
11
- [![skills](https://img.shields.io/badge/skills-272-63d68a?labelColor=12161c)](#the-catalog)
11
+ [![skills](https://img.shields.io/badge/skills-269-63d68a?labelColor=12161c)](#the-catalog)
12
12
  [![license](https://img.shields.io/badge/license-MIT-63d68a?labelColor=12161c)](LICENSE)
13
13
  [![stars](https://img.shields.io/github/stars/ericrisco/rsc-harness?color=63d68a&labelColor=12161c)](https://github.com/ericrisco/rsc-harness/stargazers)
14
14
 
@@ -60,7 +60,7 @@ The model is the brain your agent rents, and you already have it. rsc adds the r
60
60
  | --- | --- | --- |
61
61
  | **Memory** | `02-DOCS/` | A wiki the agent reads before it works and keeps up to date while it works. |
62
62
  | **Hands** | `01-TOOLS/` | One folder per tool, with a test that proves the connection works. |
63
- | **Trade** | skills | Only the skills your project needs: 272 available, a handful installed. |
63
+ | **Trade** | skills | Only the skills your project needs: 269 available, a handful installed. |
64
64
  | **Reflexes** | hooks | Rules that hold even when the agent forgets them mid-session. |
65
65
 
66
66
  ### Why documentation comes first
@@ -405,6 +405,9 @@ file, and `rsc agents reset <name>` takes rsc's version back after a backup.
405
405
 
406
406
  ## CLI
407
407
 
408
+ `rsc` below is short for `npx @ericrisco/rsc`. Without a global install (`npm i -g @ericrisco/rsc`),
409
+ the bare `rsc` answers `command not found`: type the `npx` form.
410
+
408
411
  ```bash
409
412
  # Setup
410
413
  rsc onboard # plain-language onboarding; writes nothing until you accept
@@ -429,7 +432,7 @@ rsc ingest notas.md --topic crm # move a file into 02-DOCS/raw/ (verified c
429
432
  rsc copy rules | check ad.txt # the phrases this project forbids, and a check before publishing
430
433
 
431
434
  # Memory and diagnostics
432
- rsc memory status | off | resume
435
+ rsc memory status | off | resume # session continuity; «recuerda esto» goes to 02-DOCS/wiki/
433
436
  rsc doctor # harness health and onboarding readiness
434
437
  rsc repair # put the harness back to what is declared
435
438
  rsc backups | restore latest # project-local snapshots
@@ -468,7 +471,7 @@ snapshots the project first, so `rsc restore latest` undoes a bad update.
468
471
 
469
472
  ## The catalog
470
473
 
471
- 272 skills, grouped by what you are trying to do. Click any skill to read its `SKILL.md`. It fires on
474
+ 269 skills, grouped by what you are trying to do. Click any skill to read its `SKILL.md`. It fires on
472
475
  its own when a task matches.
473
476
 
474
477
  ### 🧭 Core & control plane
@@ -561,11 +564,11 @@ whether, what and which platform.
561
564
 
562
565
  ### 🌀 Motion & interface craft
563
566
 
564
- [motion-craft](skills/motion-craft/) · [ui-engineering](skills/ui-engineering/) · [variant-explorer](skills/variant-explorer/) · [scroll-film](skills/scroll-film/)
567
+ [ui-engineering](skills/ui-engineering/) · [variant-explorer](skills/variant-explorer/) · [scroll-film](skills/scroll-film/)
565
568
 
566
569
  ### 🎨 Design & content craft
567
570
 
568
- [design-loop](skills/design-loop/) · [design](skills/design/) · [design-dna](skills/design-dna/) · [presentations](skills/presentations/) · [course-storytelling](skills/course-storytelling/) · [course-builder](skills/course-builder/) · [technical-writing](skills/technical-writing/) · [translation-l10n](skills/translation-l10n/)
571
+ [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/)
569
572
 
570
573
  ### 🧠 Knowledge & meta
571
574
 
@@ -626,7 +629,8 @@ Most of this catalog is written here. These are not, and they keep their author'
626
629
  | Skills | Source | License |
627
630
  | --- | --- | --- |
628
631
  | `design-eng` · `animate` · `animate-expo` · `review-animations` · `improve-animations` · `find-animation-opportunities` · `animation-vocabulary` · `apple-design` · `prototype` · `pick-ui-library` · `write-swift` · `ask-sonner` | [emilkowalski/skills](https://github.com/emilkowalski/skills) by Emil Kowalski, commit `d23d7f8` | MIT |
629
- | part of the AI-tell corpus in `design` | [Leonxlnx/taste-skill](https://github.com/Leonxlnx/taste-skill) | MIT |
632
+ | the engine of `design` (`skills/design/engine/`: direction draw, browser inspector, study library), shipped unmodified | [Leonxlnx/taste-skill](https://github.com/Leonxlnx/taste-skill) v2.1.4 | MIT |
633
+ | the four modes, the fresh review and the `DESIGN.md` record in `design` (text rewritten) | [pbakaus/impeccable](https://github.com/pbakaus/impeccable) by Paul Bakaus, `skill-v4.7.0` | Apache-2.0 |
630
634
  | the answer-first habits in `orient` | [ayghri/i-have-adhd](https://github.com/ayghri/i-have-adhd) | MIT |
631
635
  | the scroll-scrubbed camera flight, the frame handoff between clips and the phone fixes behind `scroll-film` (prose and engine rewritten) | [oso95/scroll-world](https://github.com/oso95/scroll-world) | MIT |
632
636
 
package/manifest.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": "3.1.4",
2
+ "version": "3.3.1",
3
3
  "counts": {
4
- "skills": 272,
4
+ "skills": 269,
5
5
  "agents": 34,
6
6
  "commands": 53,
7
7
  "fixedCommands": 20
@@ -1311,62 +1311,29 @@
1311
1311
  },
1312
1312
  {
1313
1313
  "id": "design",
1314
- "description": "Use when designing or refreshing a web UI or landing page — visual concept, type/color/spacing/motion tokens, composition, rescuing a UI that reads AI-generic, or a graded design review. Brand-grounded and research-first; ships Tailwind v4 + Next.js 15 under WCAG 2.2 AA and Core Web Vitals budgets. NOT the words on the page (that is `marketing`), NOT the App Router build (that is `nextjs`).",
1314
+ "description": "Use when designing, redesigning, restyling or reviewing a web page or app screen (landing, product site, portfolio, dashboard, docs) or when a UI looks generic or AI-made. Deals a researched direction, takes the idea from the subject, uses real pictures, proves it in a browser. NOT the words (landing-copy), NOT component state (ui-engineering).",
1315
1315
  "tags": [
1316
1316
  "design",
1317
- "ux",
1318
1317
  "ui",
1318
+ "ux",
1319
1319
  "landing",
1320
- "conversion"
1320
+ "dashboard",
1321
+ "frontend",
1322
+ "taste"
1321
1323
  ],
1322
1324
  "recommends": [
1323
- "design-loop",
1324
- "design-dna",
1325
- "nextjs",
1326
- "marketing"
1325
+ "landing-copy",
1326
+ "ui-engineering",
1327
+ "accessibility",
1328
+ "brand-identity",
1329
+ "nextjs"
1327
1330
  ],
1328
1331
  "profiles": [
1332
+ "minimal",
1333
+ "core",
1329
1334
  "full"
1330
1335
  ]
1331
1336
  },
1332
- {
1333
- "id": "design-dna",
1334
- "description": "Use when a design has won and its look must survive: codify it into a permanent style skill with measured ratios, bans and tests that can fail, then build new pieces in that exact look. Fires on 'turn this into a skill', 'keep the same style', 'my output drifted'. NOT finding the winner (that is `design-loop`), NOT the words (that is `marketing`).",
1335
- "tags": [
1336
- "design",
1337
- "style",
1338
- "dna",
1339
- "codify",
1340
- "skill-factory",
1341
- "consistency"
1342
- ],
1343
- "recommends": [
1344
- "design-loop",
1345
- "design",
1346
- "nextjs",
1347
- "marketing"
1348
- ],
1349
- "profiles": []
1350
- },
1351
- {
1352
- "id": "design-loop",
1353
- "description": "Use when something must be built well and there is a real reference it should beat: turn what makes the reference good into measured mechanisms, then run a builder and three fresh-context critics until all three pass. Fires on 'design loop', 'make it as good as <site>', 'it looks generic'. NOT keeping an already-won look (that is `design-dna`).",
1354
- "tags": [
1355
- "design",
1356
- "critique",
1357
- "loop",
1358
- "reference",
1359
- "quality",
1360
- "convergence"
1361
- ],
1362
- "recommends": [
1363
- "design",
1364
- "design-dna",
1365
- "marketing",
1366
- "nextjs"
1367
- ],
1368
- "profiles": []
1369
- },
1370
1337
  {
1371
1338
  "id": "digitalocean",
1372
1339
  "description": "Use when deploying or operating a workload on DigitalOcean — Droplet vs App Platform vs Functions, doctl, app spec YAML, Managed Postgres/MySQL/Valkey on the VPC, S3-compatible Spaces + CDN. NOT host-agnostic CI/CD or rollback strategy (that is `deployment`), NOT a bare Hetzner VPS (that is `hetzner`), NOT another managed PaaS (that is `railway`).",
@@ -3131,23 +3098,6 @@
3131
3098
  ],
3132
3099
  "profiles": []
3133
3100
  },
3134
- {
3135
- "id": "motion-craft",
3136
- "description": "Use when an interface moves and the movement has to feel right — durations and easing, what must never animate, fixing motion that reads sluggish, cheap or janky, and reduced-motion. Web and native. NOT the visual system (that is `design`), NOT the graded critique (that is `design-loop`).",
3137
- "tags": [
3138
- "motion",
3139
- "animation",
3140
- "interface",
3141
- "craft",
3142
- "frontend"
3143
- ],
3144
- "recommends": [
3145
- "design"
3146
- ],
3147
- "profiles": [
3148
- "full"
3149
- ]
3150
- },
3151
3101
  {
3152
3102
  "id": "mysql",
3153
3103
  "description": "Use when designing, querying, indexing or operating a MySQL or MariaDB database and engine-specific behaviour matters — schema and type choices, index design, reading EXPLAIN, online schema change, replication and replica lag, locking and InnoDB deadlocks, charset traps, and server config. NOT portable SELECT/JOIN/window-function craft (that is `sql`), NOT PostgreSQL engine behaviour like VACUUM or JSONB (that is `postgresdb`), NOT the PlanetScale/Vitess branch-and-deploy workflow (that is `planetscale`).",
@@ -5170,8 +5120,7 @@
5170
5120
  "craft"
5171
5121
  ],
5172
5122
  "recommends": [
5173
- "design",
5174
- "motion-craft"
5123
+ "design"
5175
5124
  ],
5176
5125
  "profiles": [
5177
5126
  "core",
@@ -5295,7 +5244,7 @@
5295
5244
  },
5296
5245
  {
5297
5246
  "id": "variant-explorer",
5298
- "description": "Use when someone wants OPTIONS rather than an answer — 'show me a few versions', picking between approaches by seeing them. Genuinely different candidates, cheap to throw away, trade-off named. NOT the critique that judges one (`design-loop`), NOT the spec (`specify`).",
5247
+ "description": "Use when someone wants OPTIONS rather than an answer — 'show me a few versions', picking between approaches by seeing them. Genuinely different candidates, cheap to throw away, trade-off named. NOT the critique that judges one (`design`), NOT the spec (`specify`).",
5299
5248
  "tags": [
5300
5249
  "prototyping",
5301
5250
  "divergence",
@@ -5304,7 +5253,7 @@
5304
5253
  "decision"
5305
5254
  ],
5306
5255
  "recommends": [
5307
- "design-loop"
5256
+ "design"
5308
5257
  ],
5309
5258
  "profiles": [
5310
5259
  "full"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ericrisco/rsc",
3
- "version": "3.1.4",
3
+ "version": "3.3.1",
4
4
  "description": "A guided harness builder that turns your goal into a minimal, verified AI-agent setup using strict best practices.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,6 +19,7 @@
19
19
  "knowledge:doctor": "node scripts/knowledge-doctor.js",
20
20
  "spec:gate": "node scripts/spec-gate.js",
21
21
  "routing:audit": "node scripts/routing-audit.js",
22
+ "design:upstream": "node scripts/design-upstream.js",
22
23
  "originality:check": "node scripts/originality-check.js",
23
24
  "test": "node --test",
24
25
  "coverage": "c8 --reporter=text node --test",
@@ -115,6 +116,10 @@
115
116
  {
116
117
  "fixedIn": "2.1.0",
117
118
  "symptom": "Answers were long and leaned on hidden reasoning, and onboarding asked an accompaniment level few could answer; now: short stand-alone sentences, one question"
119
+ },
120
+ {
121
+ "fixedIn": "3.3.0",
122
+ "symptom": "Pages and screens designed with rsc came out generic and AI-looking, and most projects had no design skill installed at all (found by Carlos del Corral)"
118
123
  }
119
124
  ]
120
125
  }
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ // design-upstream.js — is the `design` engine behind the projects it comes from?
3
+ //
4
+ // `skills/design/engine/` is taste-skill shipped unmodified, and three of its references adapt
5
+ // impeccable's text. Both upstreams ship weekly. Nothing reminded anyone, so the previous design
6
+ // skill drifted into the state that got it rebuilt (spec design-from-scratch). This is the reminder.
7
+ //
8
+ // node scripts/design-upstream.js report: silent and exit 0 when current,
9
+ // one line per upstream that moved and exit 1
10
+ // node scripts/design-upstream.js --sync DIR copy a REVIEWED taste-skill checkout over engine/
11
+ //
12
+ // It never downloads code to apply it. Bringing a new version in is a person reading the diff and
13
+ // running --sync on a checkout they cloned themselves (a public skill is untrusted input).
14
+ import { readFileSync, writeFileSync, rmSync, cpSync, existsSync } from 'node:fs';
15
+ import { join, dirname } from 'node:path';
16
+ import { fileURLToPath } from 'node:url';
17
+ import { execFileSync } from 'node:child_process';
18
+
19
+ const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
20
+ export const ENGINE = join(ROOT, 'skills', 'design', 'engine');
21
+ const RUNTIME = ['scripts', 'library', 'assets', 'references'];
22
+
23
+ export function readUpstream(engine = ENGINE) {
24
+ return JSON.parse(readFileSync(join(engine, 'UPSTREAM.json'), 'utf8'));
25
+ }
26
+
27
+ async function getJson(fetchImpl, url) {
28
+ const res = await fetchImpl(url, { headers: { accept: 'application/vnd.github+json', 'user-agent': 'rsc-design-upstream' } });
29
+ if (!res.ok) throw new Error(`${url} → HTTP ${res.status}`);
30
+ return res.json();
31
+ }
32
+
33
+ /** One entry per upstream that moved; an empty list means the engine is current. */
34
+ export async function checkUpstream({ upstream = readUpstream(), fetchImpl = fetch } = {}) {
35
+ const moved = [];
36
+ const t = upstream['taste-skill'];
37
+ const commits = await getJson(fetchImpl, `https://api.github.com/repos/${t.repo}/commits?path=${t.path}&per_page=1`);
38
+ const latest = commits[0]?.sha;
39
+ // Different ids do not mean newer: the shipped commit is often a merge that already contains the
40
+ // latest commit on the path. Only a latest commit AHEAD of what shipped is news.
41
+ const ahead = latest && latest !== t.commit
42
+ && ['ahead', 'diverged'].includes((await getJson(fetchImpl, `https://api.github.com/repos/${t.repo}/compare/${t.commit}...${latest}`)).status);
43
+ if (ahead) {
44
+ moved.push({ id: 'taste-skill', shipped: t.commit.slice(0, 7), latest: latest.slice(0, 7), url: `https://github.com/${t.repo}/compare/${t.commit}...${latest}` });
45
+ }
46
+ const i = upstream.impeccable;
47
+ const releases = await getJson(fetchImpl, `https://api.github.com/repos/${i.repo}/releases?per_page=30`);
48
+ const skill = releases.find((r) => typeof r.tag_name === 'string' && r.tag_name.startsWith('skill-v'));
49
+ if (skill && skill.tag_name !== i.version) {
50
+ moved.push({ id: 'impeccable', shipped: i.version, latest: skill.tag_name, url: `https://github.com/${i.repo}/releases/tag/${skill.tag_name}` });
51
+ }
52
+ return moved;
53
+ }
54
+
55
+ /** Copy a reviewed taste-skill checkout over engine/, and record which commit it was. */
56
+ export function syncTaste(checkout, engine = ENGINE) {
57
+ const src = join(checkout, 'skills', 'taste-skill');
58
+ if (!existsSync(join(src, 'SKILL.md'))) throw new Error(`${checkout} is not a taste-skill checkout (no skills/taste-skill/SKILL.md)`);
59
+ for (const dir of RUNTIME) {
60
+ rmSync(join(engine, dir), { recursive: true, force: true });
61
+ if (existsSync(join(src, dir))) cpSync(join(src, dir), join(engine, dir), { recursive: true });
62
+ }
63
+ cpSync(join(checkout, 'LICENSE'), join(engine, 'LICENSE'));
64
+ // RUN.md is the upstream SKILL.md without its front matter, so it is never discovered as a skill.
65
+ writeFileSync(join(engine, 'RUN.md'), readFileSync(join(src, 'SKILL.md'), 'utf8').replace(/^---\n[\s\S]*?\n---\n/, ''));
66
+ const upstream = readUpstream(engine);
67
+ // The last commit that touched the skill folder; checkUpstream asks GitHub whether anything newer
68
+ // on that path is ahead of it.
69
+ upstream['taste-skill'].commit = execFileSync('git', ['-C', checkout, 'log', '-1', '--format=%H', '--', 'skills/taste-skill'], { encoding: 'utf8' }).trim();
70
+ const changelog = join(checkout, 'CHANGELOG.md');
71
+ const version = existsSync(changelog) && /^## (\d+\.\d+\.\d+)/m.exec(readFileSync(changelog, 'utf8'));
72
+ if (version) upstream['taste-skill'].version = version[1];
73
+ writeFileSync(join(engine, 'UPSTREAM.json'), `${JSON.stringify(upstream, null, 2)}\n`);
74
+ return upstream['taste-skill'];
75
+ }
76
+
77
+ async function main() {
78
+ const at = process.argv.indexOf('--sync');
79
+ if (at !== -1) {
80
+ const synced = syncTaste(process.argv[at + 1]);
81
+ console.log(`engine synced to taste-skill ${synced.version} (${synced.commit.slice(0, 7)}). Run the tests and read the diff before committing.`);
82
+ return;
83
+ }
84
+ const moved = await checkUpstream();
85
+ for (const m of moved) console.log(`${m.id}: shipped ${m.shipped}, upstream ${m.latest} → ${m.url}`);
86
+ if (moved.length) {
87
+ console.log('Review the change, clone it yourself, then: node scripts/design-upstream.js --sync <taste-skill checkout>');
88
+ process.exitCode = 1;
89
+ }
90
+ }
91
+
92
+ if (import.meta.url === `file://${process.argv[1]}`) main().catch((e) => { console.error(e.message); process.exitCode = 2; });
package/scripts/doctor.js CHANGED
@@ -11,8 +11,6 @@ import { readManifest as readProjectManifest } from './lib/manifest-file.js';
11
11
  import { listBackups } from './lib/backups.js';
12
12
  import { SDD_GATE_TEXT } from '../targets/hook-once.mjs';
13
13
  import { isEnabled, checkSello, readSello, countFindings, readEffectiveConfig, validateRiskConfig } from '../targets/sello.mjs';
14
- import { designIdentity } from './lib/design-identity.js';
15
- import { startingPointSummary } from './lib/starting-point.js';
16
14
  import { countGaps, listSkills, listAgents } from './lib/capabilities.js';
17
15
  import { resolveCommands, commandPath, targetHasCommands } from '../targets/commands.js';
18
16
  import { inspectMemoryWiring } from '../targets/memory.js';
@@ -104,17 +102,6 @@ export function missingHookScripts({ target, home = homedir(), cwd = process.cwd
104
102
  // Is the post-merge trigger actually armed in this clone? Three states, because they need three
105
103
  // different answers: armed, absent (repair it), or someone else's (leave it — chaining is our job
106
104
  // at install time, and overwriting a husky hook to fix a convenience would be indefensible).
107
- // The skills that read or write a design identity (02-DOCS/wiki/brand/) or a starting point. The
108
- // state is always reported; the FIX — "run design-loop, then design-dna" — is advice, and advice needs
109
- // evidence. A todo web app with none of these installed was told to run two skills it does not have
110
- // and never asked for (E2E 2026-10-07).
111
- const DESIGN_SKILLS = new Set(['design', 'design-loop', 'design-dna', 'brand-voice', 'content-engine', 'marketing', 'presentations', 'make']);
112
- function withoutUnfoundedFix(summary, inPlay) {
113
- if (inPlay || !summary || !summary.fix) return summary;
114
- const { fix, ...rest } = summary;
115
- return { ...rest, note: 'no design skill is installed here, so nothing is recommended' };
116
- }
117
-
118
105
  function worktreeCleanupStatus(root, policy) {
119
106
  if (!existsSync(join(root, '.git'))) return { state: 'not-a-repo' };
120
107
  if (existsSync(join(root, '.rsc', '.no-worktree-cleanup'))) return { state: 'off-by-choice' };
@@ -250,9 +237,6 @@ export function doctor({ target, home, cwd }) {
250
237
  const path = agentPath(target, root, id);
251
238
  return path && !existsSync(path);
252
239
  }).map((id) => ({ id, path: agentPath(target, root, id), action: 'Run `npx @ericrisco/rsc sync` to restore this managed agent.' }));
253
- // What THIS harness installed, not every skill visible from here: a design skill in the user's
254
- // global scope is how a todo app's doctor came to recommend design-dna (E2E 2026-10-07).
255
- const designInPlay = Object.keys(state.skills || {}).some((id) => DESIGN_SKILLS.has(id));
256
240
  const report = {
257
241
  target,
258
242
  installed: Object.keys(state.skills),
@@ -273,14 +257,6 @@ export function doctor({ target, home, cwd }) {
273
257
  worktreeHygiene: worktreeHygiene(root),
274
258
  ownSkills: ownSkillsIn(paths, readProjectManifest(root)?.ownSkills || []),
275
259
  sello: selloStatus(root),
276
- // Whether this harness has a design identity at all. `design` has always DECLARED that it
277
- // stops without one; until lib/design-identity.js nothing checked it (P2). Reported here,
278
- // never nagged about and never blocking: a missing identity is low risk (P7).
279
- designIdentity: withoutUnfoundedFix(designIdentity(root), designInPlay),
280
- // The other half of the same question: an identity is what this project settled on, a starting
281
- // point is what it has to settle FROM. Three skills promise to propose one and none could look;
282
- // this is the look. One field, not a section — a report grows for every user who runs it (P5).
283
- designStartingPoint: withoutUnfoundedFix(startingPointSummary(root), designInPlay),
284
260
  // An inert gate must never read as an armed one (the same rule the sello follows):
285
261
  // the gitmoji guard has a per-project kill switch, so say which state it is in.
286
262
  gitmojiGuard: state.policy?.gitmojiGuard === false
@@ -14,7 +14,11 @@
14
14
  // `connect-tool` joined in 3.0.13 (issue #303): rsc ships no ready-made connections, so "connect my
15
15
  // Holded" is answered by a method, not a list, and that method has to be there the first time the
16
16
  // user asks, in any kind of project. Like `unslop`, only its description is paid for on other turns.
17
- export const DEFAULT_SKILL_FLOOR = Object.freeze(['orient', 'suggest', 'unslop', 'ftd', 'connect-tool']);
17
+ //
18
+ // `design` joined in 3.3.0 (spec design-from-scratch): it was `full`-only, so most projects designed
19
+ // with no design skill at all. Only its description is paid for on other turns; the engine it ships
20
+ // (scripts and data) is never loaded into context.
21
+ export const DEFAULT_SKILL_FLOOR = Object.freeze(['orient', 'suggest', 'unslop', 'ftd', 'connect-tool', 'design']);
18
22
 
19
23
  export function withDefaultSkillFloor(skillIds = []) {
20
24
  return [...new Set([...DEFAULT_SKILL_FLOOR, ...skillIds])];
@@ -24,8 +24,8 @@ export const DOMAINS = [
24
24
  { title: 'Ship & operate — platforms', ids: ['vercel', 'netlify', 'cloudflare', 'railway', 'render', 'fly-io', 'coolify', 'hetzner', 'digitalocean', 'aws-essentials', 'gcp-essentials'] },
25
25
  { title: 'Ship & operate — devops', ids: ['docker', 'github-actions', 'git-workflow', 'domains-dns', 'monitoring', 'email-deliverability', 'scaling', 'deployment', 'deprecation'] },
26
26
  { 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'] },
27
- { title: 'Motion & interface craft', ids: ['motion-craft', 'ui-engineering', 'variant-explorer', 'scroll-film'] },
28
- { title: 'Design & content craft', ids: ['design-loop', 'design', 'design-dna', 'presentations', 'course-storytelling', 'course-builder', 'technical-writing', 'translation-l10n'] },
27
+ { title: 'Motion & interface craft', ids: ['ui-engineering', 'variant-explorer', 'scroll-film'] },
28
+ { title: 'Design & content craft', ids: ['design', 'presentations', 'course-storytelling', 'course-builder', 'technical-writing', 'translation-l10n'] },
29
29
  { title: 'Knowledge & meta', ids: ['knowledge-ops', 'codebase-onboarding', 'research-ops', 'decision-records', 'continuous-learning', 'skill-scout', 'context-budget', 'roast-me', 'fable-operator'] },
30
30
  ];
31
31
 
@@ -10,9 +10,7 @@ const OUTCOMES = {
10
10
  fastapi: 'Your API / Python backend',
11
11
  go: 'Your Go backend service',
12
12
  postgresdb: 'Store your data reliably',
13
- design: 'Make it look good and convert',
14
- 'design-loop': 'Make it as good as the site you admire',
15
- 'design-dna': 'Keep every page looking like yours',
13
+ design: 'Pages and screens that look designed, not generated',
16
14
  marketing: 'Copy that sells',
17
15
  presentations: 'On-brand presentations',
18
16
  'course-storytelling': 'Teach so it actually lands',
@@ -8,7 +8,13 @@
8
8
  //
9
9
  // `targets/clone-bootstrap.mjs` is committed into user repos and cannot import this file; it carries
10
10
  // an inline copy, and tests/retired-skills.test.js holds the two equal in behaviour.
11
- export const RETIRED_SKILLS = Object.freeze({ eli5: 'orient', 'show-me': 'orient', bro: 'unslop' });
11
+ //
12
+ // `design-loop`, `design-dna` and `motion-craft` folded into the rebuilt `design` in 3.3.0 (spec
13
+ // design-from-scratch): its engine deals the direction, measures the render and owns the motion layer.
14
+ export const RETIRED_SKILLS = Object.freeze({
15
+ eli5: 'orient', 'show-me': 'orient', bro: 'unslop',
16
+ 'design-loop': 'design', 'design-dna': 'design', 'motion-craft': 'design',
17
+ });
12
18
 
13
19
  const retiredTo = (id) => (Object.hasOwn(RETIRED_SKILLS, id) ? RETIRED_SKILLS[id] : id);
14
20
 
@@ -0,0 +1,191 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to the Licensor for inclusion in the Work by the copyright
52
+ owner or by an individual or Legal Entity authorized to submit on
53
+ behalf of the copyright owner. For the purposes of this definition,
54
+ "submitted" means any form of electronic, verbal, or written
55
+ communication sent to the Licensor or its representatives, including
56
+ but not limited to communication on electronic mailing lists, source
57
+ code control systems, and issue tracking systems that are managed by,
58
+ or on behalf of, the Licensor for the purpose of discussing and
59
+ improving the Work, but excluding communication that is conspicuously
60
+ marked or otherwise designated in writing by the copyright owner as
61
+ "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ Copyright 2025 Paul Bakaus
180
+
181
+ Licensed under the Apache License, Version 2.0 (the "License");
182
+ you may not use this file except in compliance with the License.
183
+ You may obtain a copy of the License at
184
+
185
+ http://www.apache.org/licenses/LICENSE-2.0
186
+
187
+ Unless required by applicable law or agreed to in writing, software
188
+ distributed under the License is distributed on an "AS IS" BASIS,
189
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190
+ See the License for the specific language governing permissions and
191
+ limitations under the License.