@damiangilgonzalez/harness 1.3.11 → 1.3.13

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 (61) hide show
  1. package/README.md +31 -9
  2. package/manifest.json +1 -1
  3. package/package.json +3 -2
  4. package/scripts/doctor.js +109 -2
  5. package/scripts/install-apply.js +127 -7
  6. package/scripts/lib/capabilities.js +19 -2
  7. package/scripts/lib/divergence.js +8 -1
  8. package/scripts/lib/onboarding-apply.js +18 -1
  9. package/scripts/lib/onboarding.js +27 -2
  10. package/scripts/lib/versions.js +31 -0
  11. package/scripts/rsc.js +66 -16
  12. package/skills/animar/SKILL.md +1 -0
  13. package/skills/claude-project-setup/SKILL.md +1 -0
  14. package/skills/code-review/SKILL.md +1 -0
  15. package/skills/diseno-apple/SKILL.md +1 -0
  16. package/skills/diseno-landing/SKILL.md +1 -0
  17. package/skills/domain-modeling/SKILL.md +1 -0
  18. package/skills/flujo-interfaz/SKILL.md +1 -0
  19. package/skills/grill-me/SKILL.md +1 -0
  20. package/skills/grill-with-docs/SKILL.md +1 -0
  21. package/skills/grilling/SKILL.md +1 -0
  22. package/skills/handoff/SKILL.md +1 -0
  23. package/skills/implement/SKILL.md +1 -0
  24. package/skills/ingeniero-diseno-web/SKILL.md +1 -0
  25. package/skills/leyes-de-percepcion/SKILL.md +1 -0
  26. package/skills/leyes-de-retencion/SKILL.md +1 -0
  27. package/skills/mejor-accesibilidad/SKILL.md +1 -0
  28. package/skills/mejor-colores/SKILL.md +1 -0
  29. package/skills/mejor-layout/SKILL.md +1 -0
  30. package/skills/mejor-redaccion/SKILL.md +1 -0
  31. package/skills/mejor-tipografia/SKILL.md +1 -0
  32. package/skills/mejor-ui/SKILL.md +1 -0
  33. package/skills/muscle-memory/SKILL.md +1 -0
  34. package/skills/prototype/SKILL.md +1 -0
  35. package/skills/research/SKILL.md +1 -0
  36. package/skills/revision-de-cambios/SKILL.md +1 -0
  37. package/skills/revision-interfaz/SKILL.md +1 -0
  38. package/skills/sitios-calidad-premio/SKILL.md +1 -0
  39. package/skills/suggest/SKILL.md +10 -9
  40. package/skills/tastemaker/SKILL.md +1 -0
  41. package/skills/teach/SKILL.md +1 -0
  42. package/skills/to-questionnaire/SKILL.md +1 -0
  43. package/skills/to-spec/SKILL.md +1 -0
  44. package/skills/to-tickets/SKILL.md +1 -0
  45. package/skills/video-a-superprompt/SKILL.md +1 -0
  46. package/skills/vocabulario-animacion/SKILL.md +1 -0
  47. package/skills/wait-what/SKILL.md +1 -0
  48. package/skills/wayfinder/SKILL.md +1 -0
  49. package/skills/write-adr/SKILL.md +1 -0
  50. package/skills/writing-for-agents/SKILL.md +1 -0
  51. package/targets/_md-block.js +8 -1
  52. package/targets/agents-md-shadow.js +153 -0
  53. package/targets/agents.js +9 -2
  54. package/targets/claude.js +52 -11
  55. package/targets/clone-bootstrap.mjs +454 -0
  56. package/targets/gitmoji-guard.mjs +30 -3
  57. package/targets/opt-outs.js +40 -0
  58. package/targets/session-memory-adapter.mjs +70 -14
  59. package/targets/session-memory-core.mjs +45 -7
  60. package/targets/session-start.mjs +63 -10
  61. package/targets/worktree-reaper.mjs +174 -10
@@ -0,0 +1,31 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ // Which rsc is running, and which rsc this project was last built with. Two different numbers, and
6
+ // the gap between them is where a published fix fails to arrive: hooks are materialized as copies
7
+ // under `.rsc/`, so a release changes nothing in a project until someone syncs it. Nobody could see
8
+ // that gap before — there was no `--version`, and bug reports arrived without one.
9
+
10
+ const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
11
+ export const CLI_VERSION = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8')).version;
12
+
13
+ /** `.rsc/.version` is written at install and at every sync — the version this project's hooks came from. */
14
+ export function installedVersion(root) {
15
+ try { return readFileSync(join(root, '.rsc', '.version'), 'utf8').trim() || null; } catch { return null; }
16
+ }
17
+
18
+ export function isNewer(a, b) {
19
+ const pa = String(a).split('.').map(Number);
20
+ const pb = String(b).split('.').map(Number);
21
+ for (let i = 0; i < 3; i++) {
22
+ if ((pa[i] || 0) > (pb[i] || 0)) return true;
23
+ if ((pa[i] || 0) < (pb[i] || 0)) return false;
24
+ }
25
+ return false;
26
+ }
27
+
28
+ export function versionReport(root) {
29
+ const installed = installedVersion(root);
30
+ return { cli: CLI_VERSION, installed, behind: Boolean(installed && isNewer(CLI_VERSION, installed)) };
31
+ }
package/scripts/rsc.js CHANGED
@@ -16,6 +16,7 @@ import { runUpgrade } from './lib/upgrade.js';
16
16
  import { diagnose, repair } from './lib/repair.js';
17
17
  import { DEFAULT_SKILL_FLOOR, withDefaultSkillFloor } from './lib/default-skill-floor.js';
18
18
  import { readManifest, writeManifest } from './lib/manifest-file.js';
19
+ import { versionReport } from './lib/versions.js';
19
20
  import {
20
21
  normalizeOnboarding, missingOnboardingFields, scanProject,
21
22
  buildOnboardingPlan, decodeGoal, encodeGoal, identifyPlan, recommendDeferredComponents,
@@ -23,6 +24,20 @@ import {
23
24
  import { applyAcceptedOnboarding, verifyOnboarding, ensureHarnessSkeleton, harnessReadiness } from './lib/onboarding-apply.js';
24
25
 
25
26
  const rawArgv = process.argv.slice(2);
27
+
28
+ // `rsc --version` — answered before anything else runs, offline, and in a shape a bug report can
29
+ // paste. Two numbers because there are two things: the CLI you just ran, and the harness this
30
+ // project was built with. When they differ the project is running old hooks, and a fix that was
31
+ // published may simply not be here yet.
32
+ if (['--version', '-v', 'version'].includes(rawArgv[0])) {
33
+ const v = versionReport(process.cwd());
34
+ const lines = [`rsc ${v.cli}`];
35
+ if (v.installed) lines.push(`installed in this project: ${v.installed}${v.behind ? ' (behind)' : ''}`);
36
+ else lines.push('installed in this project: none');
37
+ if (v.behind) lines.push('This project runs older hooks than this CLI. To catch up, run here:', ' npx @damiangilgonzalez/harness@latest');
38
+ process.stdout.write(`${lines.join('\n')}\n`);
39
+ process.exit(0);
40
+ }
26
41
  const GLOBAL_VALUE_FLAGS = new Set([
27
42
  '--target', '--technical-level', '--accompaniment', '--project-kind', '--goal', '--goal-base64', '--software-scope', '--accept-plan',
28
43
  ]);
@@ -486,7 +501,18 @@ function printContextBudget(b) {
486
501
  say('════════════════════════════════════════════════\n');
487
502
  }
488
503
 
489
- async function wizard(flagTargets) {
504
+ async function syncDeclared(targets, dry = false) {
505
+ for (const t of targets) {
506
+ const result = await syncInstalled({ target: t, dryRun: dry });
507
+ const verb = dry ? 'Would sync' : 'Synced';
508
+ say(`${verb} ${t}: ${result.synced.length ? result.synced.join(', ') : '(nothing to sync)'}`);
509
+ if (dry && result.paths?.length) {
510
+ for (const p of result.paths) say(` ${p}`);
511
+ }
512
+ }
513
+ }
514
+
515
+ async function wizard(flagTargets, declaredTargets = []) {
490
516
  const m = loadManifest();
491
517
  await banner(m.counts.skills);
492
518
  say(' the skill catalog for your assistant (Claude Code · Codex · Cursor · Gemini · Antigravity)\n');
@@ -496,12 +522,16 @@ async function wizard(flagTargets) {
496
522
  const baseIds = skillsForProfile(m, 'minimal');
497
523
  // Navigable loop: esc / "← Back" / "no" all return here instead of quitting.
498
524
  for (;;) {
525
+ const declared = readManifest();
499
526
  const choice = await select('What do you want to do?', [
527
+ // First, because it is what someone who already has a harness came here for nine times in ten.
528
+ ...(declared ? [{ key: 'update', label: `Update this project — keeps its ${declared.skills.length} skills, refreshes hooks and content` }] : []),
500
529
  { key: 'base', label: `Base install — the essentials (${baseIds.length} skills)` },
501
530
  { key: 'workflow', label: 'Base + tu flujo de trabajo — grill-with-docs → to-spec → plan o tickets' },
502
531
  { key: 'manual', label: 'Pick skills by hand, by area' },
503
532
  ]);
504
533
  if (choice === null) { say('\nOK — nothing installed. Anytime: npx @damiangilgonzalez/harness'); return; }
534
+ if (choice === 'update') return syncDeclared(declaredTargets);
505
535
 
506
536
  let ids;
507
537
  if (choice === 'base') ids = baseIds;
@@ -560,6 +590,27 @@ async function guardCollisions(targets, ids) {
560
590
  return confirm('Replace them anyway?');
561
591
  }
562
592
 
593
+ // The governed list that `sync` reads lives INSIDE the onboarding receipt, not in `manifest.skills`.
594
+ // Updating one without the other is what deleted users' skills: `add` installed a skill and recorded
595
+ // it in `manifest.skills`, `sync` then read a governed list that predated the install, and pruned
596
+ // everything absent from it — recursively. Reported by a user, reproduced 2026-09-17: nine declared
597
+ // skills against eight governed, visible in the manifest before sync was even run.
598
+ //
599
+ // So the two travel together, always. Any command that changes what is installed carries both, and
600
+ // `applyInstall` persists the receipt rather than conserving the stale one.
601
+ function governedBy(receipt, skills) {
602
+ // The receipt is hash-checked against the plan the user accepted, so its policy is NOT a place to
603
+ // record what happened afterwards: rewriting `plan.policy.skills` made every install report "the
604
+ // receipt does not match its accepted plan id", which is the integrity check doing its job.
605
+ //
606
+ // An earlier fix for the reported data loss did exactly that, and it was wrong — the right place
607
+ // was never `add`, it was `sync`, which treated the accepted plan as the only declaration and
608
+ // pruned everything absent from it. The policy still travels for hooks and agents; what must not
609
+ // travel is a rewritten receipt.
610
+ if (!receipt) return { policy: undefined, onboarding: undefined };
611
+ return { policy: { ...receipt.plan.policy, skills }, onboarding: undefined };
612
+ }
613
+
563
614
  async function main() {
564
615
  // One resolution for every command, doctor included: `doctor` used to resolve on its
565
616
  // own and could report a different assistant than the one just installed into.
@@ -589,7 +640,16 @@ async function main() {
589
640
  const target = targets[0];
590
641
  switch (cmd) {
591
642
  case undefined:
592
- return hasDeclaredHarness() ? wizard(f ? targets : null) : runOnboarding(f ? targets : []);
643
+ if (!hasDeclaredHarness()) return runOnboarding(f ? targets : []);
644
+ // A project that already has a harness: the bare command means "bring it up to date". It is
645
+ // what every update notice, the README and our own replies to users tell people to run, with
646
+ // the promise "that reinstalls and refreshes". It used to open the install wizard instead, and
647
+ // with no terminal — which is how an agent runs it when it obeys the notice — it did nothing.
648
+ // Restoring what the project already declared is not a decision, so there is nothing to ask.
649
+ // RSC_FORCE_WIZARD opens the wizard anyway, answering from piped stdin: that is how its
650
+ // choices are tested end to end, since a test has no terminal to offer.
651
+ if (!isInteractive() && !process.env.RSC_FORCE_WIZARD) return syncDeclared(targets);
652
+ return wizard(f ? targets : null, targets);
593
653
  case 'onboard':
594
654
  return runOnboarding(f ? targets : []);
595
655
  case 'reassess':
@@ -604,8 +664,8 @@ async function main() {
604
664
  const currentManifest = readManifest();
605
665
  const receipt = currentManifest?.onboarding;
606
666
  const maintainedIds = receipt ? [...new Set([...(currentManifest.skills || []), ...(receipt.plan.policy.skills || []), ...ids])].sort() : ids;
607
- const policy = receipt ? { ...receipt.plan.policy, skills: maintainedIds } : undefined;
608
- for (const t of targets) await applyInstall({ skillIds: maintainedIds, agentIds: selected.agents, target: t, policy });
667
+ const { policy, onboarding } = governedBy(receipt, maintainedIds);
668
+ for (const t of targets) await applyInstall({ skillIds: maintainedIds, agentIds: selected.agents, target: t, policy, onboarding });
609
669
  markMaintenanceDrift(`add ${requested.join(',')}`);
610
670
  say(`✅ Installed for ${targets.join(', ')}: ${requested.join(', ')}`);
611
671
  return void say(' ↻ Reload/restart your assistant so the new skill activates.');
@@ -727,18 +787,8 @@ async function main() {
727
787
  process.exitCode = 1;
728
788
  return;
729
789
  }
730
- case 'sync': {
731
- const dry = argv.includes('--dry-run');
732
- for (const t of targets) {
733
- const result = await syncInstalled({ target: t, dryRun: dry });
734
- const verb = dry ? 'Would sync' : 'Synced';
735
- say(`${verb} ${t}: ${result.synced.length ? result.synced.join(', ') : '(nothing to sync)'}`);
736
- if (dry && result.paths?.length) {
737
- for (const p of result.paths) say(` ${p}`);
738
- }
739
- }
740
- return;
741
- }
790
+ case 'sync':
791
+ return syncDeclared(targets, argv.includes('--dry-run'));
742
792
  case 'backups': {
743
793
  const backups = listBackups();
744
794
  if (!backups.length) return void say('(no backups)');
@@ -3,6 +3,7 @@ name: animar
3
3
  description: "Use when asked to animate something, add motion, make a component feel alive, or build a transition. Builds the animation from scratch, making the decisions in the order that determines whether it feels right — whether it should animate at all, for what purpose, with which tool, which properties, which curve and duration, how it is interrupted, and how it exits. Writes the implementation. For critiquing existing motion use revisar-animaciones."
4
4
  tags: ["animation", "motion", "transitions"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Construir animaciones
@@ -3,6 +3,7 @@ name: claude-project-setup
3
3
  description: "Use when starting a new project, initializing a repository for Claude Code, or when the user asks to configure CLAUDE.md, rules, commands, skills, or agents for a project."
4
4
  tags: ["setup", "claude-code", "project-init"]
5
5
  profiles: [core, ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Claude Project Setup
@@ -3,6 +3,7 @@ name: code-review
3
3
  description: "Reviews changes from a fixed point (commit, branch, tag, or merge-base) along two axes — Standards (does the code follow the repo's documented coding standards?) and Spec (does the code match what the source issue/PRD asked for?). Runs both reviews in parallel sub-agents and reports them side by side. Use when the user wants to review a branch, a PR, work in progress, or asks to \\"review from X\\"."
4
4
  tags: ["code-review", "standards", "spec-compliance"]
5
5
  profiles: [core, ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  Revisión en dos ejes del diff entre `HEAD` y un punto fijo que proporciona el usuario:
@@ -3,6 +3,7 @@ name: diseno-apple
3
3
  description: "Apple's approach to interface design and fluid, physical motion, translated to the web. Use when building or reviewing gesture-driven UI, spring animations, drag/swipe/sheet interactions, inertia and interruptible transitions, translucent materials and depth, typography (optical size, tracking, line height), reduced motion, or the design fundamentals (feedback, spatial consistency, containment) behind Apple-style interfaces."
4
4
  tags: ["design", "apple", "motion", "interface"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Diseno Apple
@@ -3,6 +3,7 @@ name: diseno-landing
3
3
  description: "Complete system for building high-conversion landing pages: intake questions, page structure, layout choice, conversion copy, SEO, plus strict visual rules for typography, spacing, radii, backgrounds, hero, icons, and motion. Use whenever building, editing, styling, reviewing, or writing copy for ANY landing page, marketing site, web UI, page section, component, or prototype, even if the user does not mention design, conversion, tokens, or a design system. Always consult it before choosing sections, headlines, CTAs, fonts, text sizes, spacing values, radii, background colors, icons, or transitions."
4
4
  tags: ["landing-page", "conversion", "design-system", "copywriting"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Diseno de landing page
@@ -3,6 +3,7 @@ name: domain-modeling
3
3
  description: "Build and refine the project's domain model. Use when the user wants to pin down domain terminology or a ubiquitous language, record an architectural decision, or when another skill needs to keep the domain model up to date."
4
4
  tags: ["domain-modeling", "glossary", "architecture"]
5
5
  profiles: [core, ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Modelado de Dominio
@@ -4,6 +4,7 @@ description: "Use when work touches a screen — building or reshaping a landing
4
4
  tags: ["ui-design", "routing", "workflow"]
5
5
  profiles: [ui, full]
6
6
  recommends: [ingeniero-diseno-web, diseno-landing, revision-interfaz]
7
+ origin: damiangil
7
8
  ---
8
9
 
9
10
  # Flujo de interfaz — quien manda en cada paso
@@ -4,6 +4,7 @@ description: "A relentless interrogation to sharpen a plan or design."
4
4
  tags: ["planning", "questioning", "decision-making"]
5
5
  disable-model-invocation: true
6
6
  profiles: [core, ui, full]
7
+ origin: damiangil
7
8
  ---
8
9
 
9
10
  Llama a la herramienta Skill con "grilling".
@@ -4,6 +4,7 @@ description: "A relentless interrogation to sharpen a plan or design, which also
4
4
  tags: ["planning", "questioning", "documentation", "adr"]
5
5
  disable-model-invocation: true
6
6
  profiles: [core, ui, full]
7
+ origin: damiangil
7
8
  ---
8
9
 
9
10
  Lanza una sesión de `/grilling`, usando la skill `/domain-modeling`.
@@ -3,6 +3,7 @@ name: grilling
3
3
  description: "Interrogates the user relentlessly about a plan, decision, or idea. Use when the user wants to stress-test their reasoning, or when they use any trigger phrase like \\"grill\\" / \\"interrogate me\\" / \\"put me to the test\\"."
4
4
  tags: ["planning", "questioning", "decision-making"]
5
5
  profiles: [core, ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  Interroga al usuario sin tregua hasta llegar a un entendimiento compartido. Represéntalo como un **árbol de decisión**: cada decisión se ramifica en las decisiones que cuelgan de ella.
@@ -3,6 +3,7 @@ name: handoff
3
3
  description: "Compacts the current conversation into a handoff document so another agent can continue the work."
4
4
  tags: ["handoff", "documentation", "continuity"]
5
5
  profiles: [core, ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  Redacta un documento de traspaso que resuma la conversación actual para que un agente nuevo pueda continuar con el trabajo.
@@ -4,6 +4,7 @@ description: "Implements a piece of work from a spec or a set of tickets."
4
4
  tags: ["implementation", "spec", "tickets"]
5
5
  disable-model-invocation: true
6
6
  profiles: [core, ui, full]
7
+ origin: damiangil
7
8
  ---
8
9
 
9
10
 
@@ -3,6 +3,7 @@ name: ingeniero-diseno-web
3
3
  description: "Build or redesign polished visual artifacts that render in a browser with HTML/CSS/JavaScript/React — pages, dashboards, prototypes, presentations, animations, UI mockups, and data visualizations. Use for visual front-end creation, design-system exploration, design critique, or explicit browser-based acceptance/QA. Not for back-end, CLI, non-visual code, or converting sources into long-form articles."
4
4
  tags: ["frontend", "web-design", "prototyping", "qa"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Ingeniero de diseno web
@@ -3,6 +3,7 @@ name: leyes-de-percepcion
3
3
  description: "Use when composing or reviewing a screen and you need to decide what the eye sees first and how things are grouped — proximity, similarity, common region, closure, continuity, figure-ground, the Von Restorff effect, and visual hierarchy. This is the package of Gestalt laws applied to interface design."
4
4
  tags: ["gestalt", "visual-perception", "ui-design"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Leyes de percepcion
@@ -3,6 +3,7 @@ name: leyes-de-retencion
3
3
  description: "Use when diagnosing why people abandon a flow halfway through, or when designing decisions, forms, steps, response times, and closing moments — Hick's law, Fitts's law, Miller's law, Jakob's law, the Doherty threshold, the Zeigarnik effect, the serial position effect, the peak-end rule, and Tesler's law."
4
4
  tags: ["retention", "ux-laws", "behavioral-design"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Leyes de retencion
@@ -3,6 +3,7 @@ name: mejor-accesibilidad
3
3
  description: "Use to bring the project up to accessibility standards and best practices — native elements vs. ARIA, focus rings, full keyboard support, focus trapping, tap target sizes, form labels, announced errors, accessible names, reduced motion, live regions, alt text, heading structure, and zoom."
4
4
  tags: ["accessibility", "a11y", "aria", "keyboard-navigation"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Accesibilidad
@@ -3,6 +3,7 @@ name: mejor-colores
3
3
  description: "Use to build a color system or answer anything about color in the project — generating palettes, using semantic tokens, converting between formats, measuring contrast, choosing a gradient's interpolation space, and setting up dark mode."
4
4
  tags: ["color", "design-tokens", "contrast", "dark-mode"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Colores
@@ -3,6 +3,7 @@ name: mejor-layout
3
3
  description: "Use when building or reviewing a screen's layout — grouping, alignment, reading order, progressive disclosure, spacing, breakpoints, translated-text growth, and RTL."
4
4
  tags: ["layout", "responsive-design", "ui-design"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Layout
@@ -3,6 +3,7 @@ name: mejor-redaccion
3
3
  description: "Use when writing or reviewing a product's copy — voice and tone, button labels, a flow's vocabulary, link text, capitalization, settings, error messages, empty states, and placeholders."
4
4
  tags: ["ux-writing", "microcopy", "content-design"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Redaccion de interfaz
@@ -3,6 +3,7 @@ name: mejor-tipografia
3
3
  description: "Use when building or reviewing typography — size scale, spacing, line height, variable fonts, OpenType features, wrapping, truncation, tabular numbers, punctuation, and all the details that make text read well across a product."
4
4
  tags: ["typography", "design-system", "readability"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Tipografia
@@ -3,6 +3,7 @@ name: mejor-ui
3
3
  description: "Use to polish and improve a project's UI — concentric border radii, optical alignment, surface depth, shadows vs. borders, interruptible animations, staggered entrances, icon transitions, press scaling, theme-switch transition suppression, and motion containment."
4
4
  tags: ["ui-polish", "visual-design", "motion"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Acabado de UI
@@ -3,6 +3,7 @@ name: muscle-memory
3
3
  description: "Python practice gym — generates short katas from the user's recent code, tracks progress, and reviews solutions. Use when the user wants to practice/keep their coding sharp, review a kata solution, or check practice progress."
4
4
  tags: ["practice", "python", "katas"]
5
5
  profiles: [core, ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Muscle Memory
@@ -3,6 +3,7 @@ name: prototype
3
3
  description: "Builds a throwaway prototype to answer a design question. Use when the user wants to check whether a state model or logic \\"feels right\\", or explore what a UI should look like."
4
4
  tags: ["prototyping", "design", "exploration"]
5
5
  profiles: [core, ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Prototipo
@@ -3,6 +3,7 @@ name: research
3
3
  description: "Researches a question against high-confidence primary sources and captures the findings as a Markdown file in the repo. Use when the person wants to research a topic, gather facts from documentation or an API, or delegate the reading work to a background agent."
4
4
  tags: ["research", "documentation", "background-agent"]
5
5
  profiles: [core, ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  Levanta un **agente en segundo plano** para hacer la investigación, así sigues trabajando mientras él lee.
@@ -4,6 +4,7 @@ description: "Reviews a CHANGE (uncommitted work, a branch, a commit range, or a
4
4
  tags: ["code-review", "diff-review", "regression"]
5
5
  disable-model-invocation: true
6
6
  profiles: [core, ui, full]
7
+ origin: damiangil
7
8
  ---
8
9
 
9
10
  # Revision de cambios
@@ -3,6 +3,7 @@ name: revision-interfaz
3
3
  description: "Combines all the `mejor-*` skills into a single interface review covering accessibility, layout, copy, typography, color, and visual polish, and consolidates a verdict ordered by impact."
4
4
  tags: ["ui-review", "accessibility", "design-audit"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Revision de interfaz
@@ -3,6 +3,7 @@ name: sitios-calidad-premio
3
3
  description: "Art-direct and implement marketing, editorial, portfolio, and landing sites that are distinctive and motion-rich, with original imagery inspired by references, standout heroes, GSAP choreography, a single smooth-scroll engine, optional Three.js shaders, honest icon and logo sourcing, photographic avatars, accessibility, and performance safeguards. Use when asked for an award-quality, premium, cinematic, interactive, high-concept, or motion-driven website."
4
4
  tags: ["award-site", "gsap", "webgl", "art-direction"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Construir sitios de calidad de premio
@@ -25,9 +25,8 @@ owns it; this is the pointer, not the manual.
25
25
  The moment someone wants something to **exist or behave differently** — build, add, change,
26
26
  integrate, "it should also…", "¿y si…?", in any language — the request earns a clear *what* and
27
27
  the user's go-ahead before any line of code lands. No skill outranks this, stack and builder
28
- skills included (`nextjs`, `react`, `fastapi`, `flutter`, `go`, `postgresdb`, `building-agents`,
29
- `design`, `chatbot`, `course-builder`, `marketing`…): they run **inside** the chain, once the plan
30
- is approved — matching strongly is not a reason to skip ahead.
28
+ skills included (`nextjs`, `fastapi`, `flutter`, `building-agents`, `design`, `marketing`…): they
29
+ run **inside** the chain, once the plan is approved — matching strongly is not a reason to skip ahead.
31
30
 
32
31
  The shape of the chain:
33
32
 
@@ -47,8 +46,8 @@ Two exceptions, and say out loud when you take one:
47
46
 
48
47
  When you cannot tell, take the clarifying step. A skipped one is where drift hides.
49
48
 
50
- Judge the **meaning**, not the wording: the trigger is semantic, so it holds in any language,
51
- including ones with no example here. A URL plus a description of desired behaviour is a feature
49
+ Judge the **meaning**, not the wording: the trigger is semantic, so it holds in any language.
50
+ A URL plus a description of desired behaviour is a feature
52
51
  request. If the user already engaged an autopilot over this chain, that one consent covers the
53
52
  whole run — advance through the phases without re-asking.
54
53
 
@@ -73,7 +72,7 @@ name it and offer it. This runs mid-conversation, not only at project start.
73
72
  `id available short description`.
74
73
  2. Pick the single best fit **by meaning**, the way you would match a request to a teammate's
75
74
  expertise — "mandar emails de bienvenida" → an email/outreach skill, though not one keyword
76
- overlaps; "login con Google" → an auth skill, not `flutter`. If nothing genuinely fits, say so
75
+ overlaps. If nothing genuinely fits, say so
77
76
  and move on: a tangential suggestion is worse than none.
78
77
  3. Ask once, plainly: "Para esto instalaría `<id>`, que aún no tienes. ¿La instalo? (sí/no)".
79
78
  4. On yes, run `npx @damiangilgonzalez/harness add <id>`, then continue the original task.
@@ -100,7 +99,6 @@ You are injected into every session, so you are the only thing that can notice a
100
99
  harness before its owner does — and its owner usually cannot, because the symptoms name
101
100
  nothing they recognise. When any of these is true, act on it **once** in the session:
102
101
 
103
- - the assistant sees no skills in a project that clearly has a harness;
104
102
  - `.rsc.json` exists and what it declares is not what is installed;
105
103
  - the same hook seems to run several times;
106
104
  - the harness is wired for an assistant that is not the one running.
@@ -108,6 +106,10 @@ nothing they recognise. When any of these is true, act on it **once** in the ses
108
106
  Run `npx @damiangilgonzalez/harness doctor`, and say in one line what is wrong **as a symptom**, not as
109
107
  a cause. Then:
110
108
 
109
+ - **Nothing built** — `.rsc.json` without `.rsc/`: a clone. Name
110
+ `npx @damiangilgonzalez/harness@<catalogVersion in .rsc.json> sync`, that exact version, **never** `@latest`
111
+ — a release nobody here adopted is drift. Ask in one line, **keep working either way**; silence
112
+ is not a no, `.rsc/.no-harness` is.
111
113
  - Anything that only puts the harness back to what was already declared — dangling links, a
112
114
  repeated hook, a layout no version uses — say you are fixing it and run
113
115
  `npx @damiangilgonzalez/harness repair`. Restoring is not deciding, and a recoverable copy is kept.
@@ -115,8 +117,7 @@ a cause. Then:
115
117
  teammate added, disarming a gate — **ask first**. A `git pull` never rewrites someone's
116
118
  machine.
117
119
 
118
- Offer once. A "no" holds for the session; a new session may look again, because the problem
119
- has not gone away. Never mention it when the harness is healthy.
120
+ Offer once per session. Never mention any of it when the harness is healthy.
120
121
 
121
122
  ## 4. First contact
122
123
 
@@ -3,6 +3,7 @@ name: tastemaker
3
3
  description: "Generates genuinely beautiful, on-brand UI instead of generic AI slop. Use whenever asked to build, design, style, or improve a UI, landing page, dashboard, app screen, or component; when a PRD needs a design pass before implementation; when the user pastes reference images or links and wants the app to look like them; or when they complain the generated UI looks generic, boring, templated, or like every other AI app. Also triggers without the word \\"design\\", with phrases like \\"make this look good\\", \\"build me the frontend for X\\", \\"this looks like just another SaaS site\\", or \\"pick up the look of this\\". Also with the verbs study or extract the look from a screenshot or URL, and audit or review why something looks AI-made."
4
4
  tags: ["ui-design", "branding", "visual-design"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Tastemaker
@@ -4,6 +4,7 @@ description: "Teaches the user a new skill or concept within this workspace. Use
4
4
  tags: ["teaching", "learning", "mentoring"]
5
5
  disable-model-invocation: true
6
6
  profiles: [minimal, core, ui, full]
7
+ origin: damiangil
7
8
  ---
8
9
 
9
10
  El usuario te ha pedido que le enseñes algo. Es una petición con estado: pretende aprender el tema a lo largo de varias sesiones.
@@ -4,6 +4,7 @@ description: "Turns a decision you cannot answer alone into a questionnaire for
4
4
  tags: ["planning", "questionnaire", "decision-making"]
5
5
  disable-model-invocation: true
6
6
  profiles: [core, ui, full]
7
+ origin: damiangil
7
8
  ---
8
9
 
9
10
  Convierte algo que el usuario no puede responder solo en un **cuestionario**: un documento Markdown que entrega a una persona para rellenarlo de forma asíncrona, o para completarlo juntos en una reunión. El destinatario tiene un conocimiento que al usuario le falta; el cuestionario se lo extrae.
@@ -4,6 +4,7 @@ description: "Turns the current conversation into a spec (PRD) and publishes it
4
4
  tags: ["spec", "prd", "issue-tracker"]
5
5
  disable-model-invocation: true
6
6
  profiles: [core, ui, full]
7
+ origin: damiangil
7
8
  ---
8
9
 
9
10
 
@@ -4,6 +4,7 @@ description: "Breaks down a plan, a spec, or the current conversation into a set
4
4
  tags: ["tickets", "planning", "issue-tracker"]
5
5
  disable-model-invocation: true
6
6
  profiles: [core, ui, full]
7
+ origin: damiangil
7
8
  ---
8
9
 
9
10
 
@@ -3,6 +3,7 @@ name: video-a-superprompt
3
3
  description: "Turns a reference video into a highly detailed recreation or inspiration prompt. Use when the user provides, mentions, uploads, links, or points to a video and asks to analyze the design, UI, animations, transitions, scroll interactions, typography, colors, assets, WebGL/Three.js, narrative, or section-by-section behavior, or to create a prompt or article that recreates the page, app, interaction, or motion system."
4
4
  tags: ["video-analysis", "prompt-engineering", "design"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # De video a superprompt
@@ -3,6 +3,7 @@ name: vocabulario-animacion
3
3
  description: "Use when someone describes a web motion effect without knowing its name (\\"that bouncy thing when a popover opens\\", \\"the iOS rubber-band scroll\\") and asks \\"what's it called when...\\". Returns the exact term so it can be requested from an AI or a designer. This is for NAMING an effect, not designing or building one."
4
4
  tags: ["animation", "vocabulary", "reference"]
5
5
  profiles: [ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Vocabulario de animacion
@@ -4,6 +4,7 @@ description: "Stop. That last message didn't land: rephrase it."
4
4
  tags: ["clarification", "communication"]
5
5
  disable-model-invocation: true
6
6
  profiles: [core, ui, full]
7
+ origin: damiangil
7
8
  ---
8
9
 
9
10
  Espera, no entiendo a dónde has llegado con esto. Vuelve a plantearlo: dame algo de contexto, habla en Inglés Técnico Simplificado ASD-STE100 (aplícalo igual en español: frases cortas, una idea por frase, vocabulario consistente), y usa el lenguaje ubicuo de `CONTEXT.md` (sigue `CONTEXT-MAP.md` hasta el correcto si el repo tiene más de uno).
@@ -4,6 +4,7 @@ description: "Plans a huge chunk of work — more than fits in a single agent se
4
4
  tags: ["planning", "issue-tracker", "large-scale-work"]
5
5
  disable-model-invocation: true
6
6
  profiles: [core, ui, full]
7
+ origin: damiangil
7
8
  ---
8
9
 
9
10
  Ha llegado una idea difusa — demasiado grande para una sola sesión de agente, y envuelta en niebla: todavía no se ve el camino de aquí al **destino**. El wayfinding trata de encontrar ese camino, no de embestir contra el destino. Esta skill traza el camino como un **mapa compartido** en el issue tracker del repo, y luego trabaja sus **tickets de decisión** — preguntas cuya resolución es una decisión, no porciones de una construcción a ejecutar — de uno en uno hasta que la ruta está clara.
@@ -3,6 +3,7 @@ name: write-adr
3
3
  description: "Use when you need to record an architecture decision, open an ADR, amend or replace an existing one, or when a change is hard to revert and someone will ask in six months why it's done this way (structural refactor, major dependency, API contract, data partitioning, module boundaries)."
4
4
  tags: ["adr", "architecture", "documentation"]
5
5
  profiles: [core, ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  # Write an ADR
@@ -3,6 +3,7 @@ name: writing-for-agents
3
3
  description: "Write documents that an agent will consume. Use when creating or editing skills, or when modifying AGENTS.md or CLAUDE.md."
4
4
  tags: ["writing", "documentation", "agents"]
5
5
  profiles: [core, ui, full]
6
+ origin: damiangil
6
7
  ---
7
8
 
8
9
  Referencia para escribir cualquier documento que consume un agente: una skill, un `AGENTS.md` / `CLAUDE.md`, un documento al que se llega por un puntero. El empaquetado cambia; la escritura no: las mismas palancas hacen predecible cada uno, porque el agente sigue el mismo *proceso* en cada ejecución en lugar de producir el mismo resultado.
@@ -1,6 +1,7 @@
1
1
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
2
2
  import { dirname } from 'node:path';
3
3
  import { linkOrCopy } from './index.js';
4
+ import { ensureShadowClaudeMd } from './agents-md-shadow.js';
4
5
 
5
6
  // Shared adapter for every assistant whose "always-on" surface is a plain
6
7
  // markdown instructions/rules file (AGENTS.md, copilot-instructions.md, a
@@ -33,7 +34,13 @@ export function wireHook(paths, sourceMd, policy = {}) {
33
34
  }
34
35
  mkdirSync(dirname(paths.hookTarget), { recursive: true });
35
36
  writeFileSync(paths.hookTarget, doc);
36
- return [paths.hookTarget];
37
+
38
+ // This file may BE the root AGENTS.md, which Claude Code 2.1.277+ reads as project instructions
39
+ // when no CLAUDE.md exists — doubling an always-on body the SessionStart hook already prints.
40
+ // No-op unless the Claude Code target is also wired here. Called from both adapters so the fix
41
+ // holds whichever assistant the user installs second. See targets/agents-md-shadow.js.
42
+ const shadow = ensureShadowClaudeMd(paths.projectRoot);
43
+ return shadow ? [paths.hookTarget, shadow] : [paths.hookTarget];
37
44
  }
38
45
 
39
46
  // Inverse of wireHook: remove the marked rsc-suggest block from the shared