@damiangilgonzalez/harness 1.3.23 → 1.3.25
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 +23 -6
- package/manifest.json +27 -3
- package/package.json +1 -1
- package/scripts/lib/default-skill-floor.js +1 -1
- package/scripts/lib/domains.js +1 -1
- package/skills/code-review/SKILL.md +10 -1
- package/skills/hardening/zonas.md +9 -1
- package/skills/nextjs/SKILL.md +2 -0
- package/skills/nextjs/references/rendering-hydration.md +53 -0
- package/skills/no-me-rayes/SKILL.md +60 -0
- package/skills/no-me-rayes/evals/cases.yaml +33 -0
- package/skills/react/SKILL.md +2 -0
- package/skills/react/references/mental-model.md +38 -0
- package/skills/secure-coding/SKILL.md +10 -1
- package/skills/secure-coding/references/pre-publish.md +47 -0
- package/skills/to-spec/SKILL.md +7 -0
- package/targets/claude.js +6 -0
- package/targets/clone-bootstrap.mjs +1 -1
- package/targets/opt-outs.js +1 -0
- package/targets/session-start.mjs +47 -0
package/README.md
CHANGED
|
@@ -61,6 +61,23 @@ Todo confluye en una rama de integración.
|
|
|
61
61
|
`code-review` revisa contra los estándares del repo y contra la spec. `pr` abre la PR con
|
|
62
62
|
resumen, evidencia y peligro de fusión.
|
|
63
63
|
|
|
64
|
+
### Seguridad y front dentro de la cadena
|
|
65
|
+
|
|
66
|
+
La cadena no cambia: ni pasos nuevos ni comandos nuevos. Lo que cambia es que dos pasos que ya
|
|
67
|
+
existían ahora piden seguridad y front **cuando el cambio los toca** (auth, un endpoint, una tabla,
|
|
68
|
+
un secreto o una pantalla):
|
|
69
|
+
|
|
70
|
+
| Cuándo | Qué pasa |
|
|
71
|
+
|---|---|
|
|
72
|
+
| Al iniciar sesión | Un aviso corto según el proyecto. Con backend, API o `.env`: los 10 puntos de seguridad. Con react, next, vue, svelte o astro: el modelo mental del front. Sin ninguno de los dos, no sale nada. |
|
|
73
|
+
| `to-spec` | La spec lleva una sección «Decisiones de seguridad y de front»: qué puntos aplican y cuáles quedan fuera a propósito. |
|
|
74
|
+
| `code-review` | El eje de Estándares suma un baseline: una ruta sin rate limit o sin validación en el servidor es `should-fix`; un secreto en el repo es `blocker`. |
|
|
75
|
+
| Antes de publicar | `secure-coding` trae la lista con una prueba por punto. Es un punto de partida; la auditoría es `hardening`. |
|
|
76
|
+
|
|
77
|
+
Los 10 puntos: rate limiting, claves fuera del código, secretos de producción en la plataforma,
|
|
78
|
+
límites por IP, entradas validadas, validación en el servidor, RLS, contraseñas con hash y datos
|
|
79
|
+
cifrados, sesiones que vencen y CORS solo con tu dominio. Se apaga con `.rsc/.no-stack-hints`.
|
|
80
|
+
|
|
64
81
|
La guía completa del método, fase a fase: [`docs/skills/`](docs/skills/).
|
|
65
82
|
|
|
66
83
|
---
|
|
@@ -107,7 +124,7 @@ Empiezas pequeño. El resto se carga bajo demanda: el harness te propone una ski
|
|
|
107
124
|
la pide, con la evidencia que lo justifica.
|
|
108
125
|
|
|
109
126
|
```bash
|
|
110
|
-
rsc install --profile minimal # la base: orient + suggest + bro + unslop + show-me + eli5 + harness + init + teach + tunel-ngrok + hardening
|
|
127
|
+
rsc install --profile minimal # la base: orient + suggest + bro + unslop + show-me + eli5 + harness + init + teach + tunel-ngrok + hardening + no-me-rayes
|
|
111
128
|
rsc install --profile core # la base + el método completo
|
|
112
129
|
rsc install --profile full # todo el catálogo
|
|
113
130
|
```
|
|
@@ -128,10 +145,10 @@ Hooks que vigilan por ti: recuerdan la cadena, piden confirmación antes de un `
|
|
|
128
145
|
|
|
129
146
|

|
|
130
147
|
|
|
131
|
-
En Claude Code quedan activados `skins`, `savvy-progress`
|
|
132
|
-
(mantiene caliente la caché, y eso gasta tokens). `superpowers` llega cuando el proyecto usa el método.
|
|
148
|
+
En Claude Code quedan activados `skins`, `savvy-progress`, `context-bar`, `prompt-enhancer`, `modelo-justo`,
|
|
149
|
+
`where-am-i` y `cache-tax` (este mantiene caliente la caché, y eso gasta tokens). `superpowers` llega cuando el proyecto usa el método.
|
|
133
150
|
|
|
134
|
-
En cifras:
|
|
151
|
+
En cifras: 297 skills, 34 agentes y 43 entradas de comando, para 17 asistentes
|
|
135
152
|
(Claude Code, Codex, Cursor, Copilot, Gemini…). Detalle en la [referencia técnica](docs/referencia-tecnica.md).
|
|
136
153
|
|
|
137
154
|
---
|
|
@@ -249,9 +266,9 @@ Guía completa: [la memoria del harness](docs/como-funciona/memoria.md).
|
|
|
249
266
|
|
|
250
267
|
## Catálogo
|
|
251
268
|
|
|
252
|
-

|
|
253
270
|
|
|
254
|
-
|
|
271
|
+
297 skills en 25 dominios: software, negocio, contenido, datos e IA.
|
|
255
272
|
Cada una se activa sola cuando la tarea encaja.
|
|
256
273
|
|
|
257
274
|
**[Ver el catálogo completo →](docs/catalogo.md)** · [Referencia técnica](docs/referencia-tecnica.md) ·
|
package/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.3.
|
|
2
|
+
"version": "1.3.25",
|
|
3
3
|
"counts": {
|
|
4
|
-
"skills":
|
|
4
|
+
"skills": 297,
|
|
5
5
|
"agents": 34,
|
|
6
6
|
"commands": 43,
|
|
7
7
|
"fixedCommands": 10
|
|
@@ -3532,6 +3532,30 @@
|
|
|
3532
3532
|
],
|
|
3533
3533
|
"profiles": []
|
|
3534
3534
|
},
|
|
3535
|
+
{
|
|
3536
|
+
"id": "no-me-rayes",
|
|
3537
|
+
"description": "Use on EVERY reply and progress update, especially after tool work or a long task: the assistant must report in short bullet points what is done, what it is doing now, what blocks it, and a final summary, each marked with its own emoji. Cuts the wall-of-text answers some models give. NOT rewriting a text to sound human (that is `bro`), NOT a plain-language explanation (that is `eli5`), NOT a session handoff document (that is `handoff`).",
|
|
3538
|
+
"tags": [
|
|
3539
|
+
"no-me-rayes",
|
|
3540
|
+
"concise",
|
|
3541
|
+
"bullets",
|
|
3542
|
+
"status-report",
|
|
3543
|
+
"progress",
|
|
3544
|
+
"emojis",
|
|
3545
|
+
"short-answers"
|
|
3546
|
+
],
|
|
3547
|
+
"recommends": [
|
|
3548
|
+
"bro",
|
|
3549
|
+
"eli5",
|
|
3550
|
+
"handoff"
|
|
3551
|
+
],
|
|
3552
|
+
"profiles": [
|
|
3553
|
+
"minimal",
|
|
3554
|
+
"core",
|
|
3555
|
+
"ui",
|
|
3556
|
+
"full"
|
|
3557
|
+
]
|
|
3558
|
+
},
|
|
3535
3559
|
{
|
|
3536
3560
|
"id": "nodejs",
|
|
3537
3561
|
"description": "Use when building or operating a plain Node.js / Express 5 backend service: project layout, async correctness, central error middleware, fail-fast config, graceful shutdown on SIGTERM. NOT DI modules/providers/guards (that is `nestjs`), NOT the type system or tsconfig (that is `typescript`), NOT REST contract design (that is `api-design`).",
|
|
@@ -4539,7 +4563,7 @@
|
|
|
4539
4563
|
},
|
|
4540
4564
|
{
|
|
4541
4565
|
"id": "secure-coding",
|
|
4542
|
-
"description": "Use when securing application code: threat-modeling a feature, security-reviewing a diff, hardening auth/authz, secrets, CORS/CSP, or fixing OWASP-class bugs (access control, injection, SSRF, supply chain) in FastAPI, Next.js, Go or Flutter. NOT running the scanners (that is security-scan), NOT agent prompt-injection guardrails (that is agent-safety).",
|
|
4566
|
+
"description": "Use when securing application code: threat-modeling a feature, security-reviewing a diff, hardening auth/authz, secrets, CORS/CSP, running the pre-publish checklist (rate limiting, RLS, server-side validation) before shipping an AI-built project, or fixing OWASP-class bugs (access control, injection, SSRF, supply chain) in FastAPI, Next.js, Go or Flutter. NOT running the scanners (that is security-scan), NOT agent prompt-injection guardrails (that is agent-safety).",
|
|
4543
4567
|
"tags": [
|
|
4544
4568
|
"security",
|
|
4545
4569
|
"owasp",
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// without paying for its body on unrelated turns. `tunel-ngrok` y `hardening` son
|
|
7
7
|
// obligatorias por decisión del usuario: van al suelo para que también lleguen con
|
|
8
8
|
// el update a los proyectos que ya existían, no solo a las instalaciones nuevas.
|
|
9
|
-
export const DEFAULT_SKILL_FLOOR = Object.freeze(['orient', 'suggest', 'bro', 'tunel-ngrok', 'hardening']);
|
|
9
|
+
export const DEFAULT_SKILL_FLOOR = Object.freeze(['orient', 'suggest', 'bro', 'tunel-ngrok', 'hardening', 'no-me-rayes']);
|
|
10
10
|
|
|
11
11
|
export function withDefaultSkillFloor(skillIds = []) {
|
|
12
12
|
return [...new Set([...DEFAULT_SKILL_FLOOR, ...skillIds])];
|
package/scripts/lib/domains.js
CHANGED
|
@@ -27,7 +27,7 @@ export const DOMAINS = [
|
|
|
27
27
|
{ title: 'Motion & interface craft', ids: ['motion-craft', 'ui-engineering', 'variant-explorer'] },
|
|
28
28
|
{ title: 'Design & content craft', ids: ['design-loop', 'design', 'design-dna', 'presentations', 'course-storytelling', 'course-builder', 'technical-writing', 'translation-l10n'] },
|
|
29
29
|
{ title: 'Knowledge & meta', ids: ['knowledge-ops', 'codebase-onboarding', 'research-ops', 'continuous-learning', 'skill-scout', 'context-budget', 'roast-me', 'show-me', 'eli5', 'fable-operator'] },
|
|
30
|
-
{ title: 'Personal catalog — workflow (Spanish)', ids: ['grill-me', 'grill-with-docs', 'grilling', 'wayfinder', 'to-spec', 'to-tickets', 'to-questionnaire', 'implement', 'implement-spec', 'pr', 'retro', 'revision-de-cambios', 'code-review', 'research', 'prototype', 'domain-modeling', 'handoff', 'write-adr', 'wait-what', 'writing-for-agents', 'claude-project-setup', 'muscle-memory', 'teach', 'tunel-ngrok', 'hardening'] },
|
|
30
|
+
{ title: 'Personal catalog — workflow (Spanish)', ids: ['grill-me', 'grill-with-docs', 'grilling', 'wayfinder', 'to-spec', 'to-tickets', 'to-questionnaire', 'implement', 'implement-spec', 'pr', 'retro', 'revision-de-cambios', 'code-review', 'research', 'prototype', 'domain-modeling', 'handoff', 'write-adr', 'wait-what', 'writing-for-agents', 'claude-project-setup', 'muscle-memory', 'teach', 'tunel-ngrok', 'hardening', 'no-me-rayes'] },
|
|
31
31
|
{ title: 'Personal catalog — interface design (Spanish)', ids: ['flujo-interfaz', 'animar', 'diseno-apple', 'diseno-landing', 'ingeniero-diseno-web', 'leyes-de-percepcion', 'leyes-de-retencion', 'mejor-accesibilidad', 'mejor-colores', 'mejor-layout', 'mejor-redaccion', 'mejor-tipografia', 'mejor-ui', 'sitios-calidad-premio', 'tastemaker', 'video-a-superprompt', 'vocabulario-animacion', 'revision-interfaz'] },
|
|
32
32
|
];
|
|
33
33
|
|
|
@@ -60,6 +60,15 @@ Cada smell se lee *qué es* → *cómo arreglarlo*; contrástalo con el diff:
|
|
|
60
60
|
- **Intermediario (Middle Man)** — una clase o función que casi solo delega hacia adelante. → córtala, llama al objetivo real directamente.
|
|
61
61
|
- **Herencia rechazada (Refused Bequest)** — una subclase o implementador que ignora o sobrescribe casi todo lo que hereda. → suelta la herencia, usa composición.
|
|
62
62
|
|
|
63
|
+
### Baseline de seguridad y de front
|
|
64
|
+
|
|
65
|
+
Cuando el diff toca una ruta, un endpoint, una tabla, un secreto, una sesión o un componente, el eje de Estándares lleva además este baseline. Es un juicio, no una violación dura, y un estándar documentado del repo lo supera. Pégalo completo en el prompt del sub-agente, que no tiene otro acceso a él:
|
|
66
|
+
|
|
67
|
+
- **Seguridad** (los 10 puntos de `secure-coding`, `references/pre-publish.md`). Una ruta nueva sin rate limit o sin validación en el servidor es un hallazgo `should-fix`, no un nit. Un secreto en el repo o con el prefijo público del framework es `blocker`. Mira también: tabla nueva sin RLS, CORS con `*` y credenciales, hash débil, sesión que no vence, consulta SQL construida a mano.
|
|
68
|
+
- **Front** (`react` y `nextjs`). Estado copiado desde props o derivado guardado en `useState`, `useEffect` que calcula en vez de sincronizar, dependencias que faltan, valores no deterministas en el primer render (`Date.now()`, `Math.random()`, `window`) que rompen la hidratación, `"use client"` demasiado arriba y secretos importados desde un componente de cliente.
|
|
69
|
+
|
|
70
|
+
Si el diff no toca nada de esto, no lo añadas.
|
|
71
|
+
|
|
63
72
|
### 4. Lanzar ambos sub-agentes en paralelo
|
|
64
73
|
|
|
65
74
|
Envía un único mensaje con dos llamadas a la herramienta `Agent`. Usa el subagente `general-purpose` para ambos.
|
|
@@ -67,7 +76,7 @@ Envía un único mensaje con dos llamadas a la herramienta `Agent`. Usa el subag
|
|
|
67
76
|
**Prompt del sub-agente de Estándares** — incluye:
|
|
68
77
|
|
|
69
78
|
- El comando de diff completo y la lista de commits.
|
|
70
|
-
- La lista de archivos-fuente de estándares que encontraste en el paso 3, **más el smell baseline del paso 3 pegado completo** — el sub-agente no tiene otro acceso a él.
|
|
79
|
+
- La lista de archivos-fuente de estándares que encontraste en el paso 3, **más el smell baseline del paso 3 pegado completo, y el baseline de seguridad y de front cuando aplique** — el sub-agente no tiene otro acceso a él.
|
|
71
80
|
- El encargo: "Reporta — por archivo/hunk donde proceda — (a) cada lugar donde el diff viola un estándar documentado: cita el estándar (archivo + la regla); y (b) cualquier smell del baseline que detectes: nómbralo y cita el hunk. Distingue violaciones duras de juicios — las infracciones de estándar documentado pueden ser duras, pero los smells del baseline son siempre juicios, y un estándar documentado del repo prevalece sobre el baseline. Sáltate lo que el tooling imponga. Menos de 400 palabras."
|
|
72
81
|
|
|
73
82
|
**Prompt del sub-agente de Spec** — incluye:
|
|
@@ -66,7 +66,15 @@ Encargo de cada subagente del paso 2 de [`SKILL.md`](SKILL.md). Copia el **marco
|
|
|
66
66
|
- longitud de los textos;
|
|
67
67
|
- inyección de prompt con efecto en las herramientas;
|
|
68
68
|
- fórmulas en el Excel.
|
|
69
|
-
- Límite de peticiones y de gasto
|
|
69
|
+
- Límite de peticiones y de gasto:
|
|
70
|
+
- por IP y por identidad, con la IP real tras el proxy;
|
|
71
|
+
- más estricto en login, OTP, registro y endpoints que cuestan dinero;
|
|
72
|
+
- un contador en memoria no vale con más de una réplica.
|
|
73
|
+
- Validación en el servidor, no solo en el navegador: rehacer a mano la petición con el campo que el formulario bloquearía.
|
|
74
|
+
- Sesiones que vencen, rotación del refresh y cookie `HttpOnly`/`Secure`/`SameSite`.
|
|
75
|
+
- Contraseñas con hash fuerte (Argon2id o bcrypt) y datos sensibles cifrados.
|
|
76
|
+
- CORS con lista de orígenes, nunca `*` con credenciales.
|
|
77
|
+
- Secretos de producción en la plataforma (Vercel, Supabase, GitHub), nunca solo en `.env` ni en el repo.
|
|
70
78
|
- Errores que filtran detalles internos, cabeceras, CSP y CORS.
|
|
71
79
|
- Front: `innerHTML` y dónde se guarda la sesión.
|
|
72
80
|
- Dependencias: si están fijadas y si algo las escanea. `npm audit` se puede lanzar porque solo lee.
|
package/skills/nextjs/SKILL.md
CHANGED
|
@@ -334,6 +334,8 @@ const r = schema.safeParse(Object.fromEntries(formData));
|
|
|
334
334
|
if (!r.success) return { status: "error", message: "Invalid" };
|
|
335
335
|
```
|
|
336
336
|
|
|
337
|
+
Server vs Client placement, what breaks hydration and the stable-first-render fix: `references/rendering-hydration.md`.
|
|
338
|
+
|
|
337
339
|
## Auth & security (deep dive → references/security.md)
|
|
338
340
|
|
|
339
341
|
Defense in depth with **three layers — middleware is NOT one of them**. Full wiring (Auth.js v5
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Rendering and hydration in the App Router
|
|
2
|
+
|
|
3
|
+
Short version of the five-word model (component, state, hooks, rendering, hydration) applied to
|
|
4
|
+
Next.js. The generic model is in `../../react/references/mental-model.md` when `react` is installed.
|
|
5
|
+
|
|
6
|
+
## Where each piece runs
|
|
7
|
+
|
|
8
|
+
| Piece | Runs | Can use | Cannot use |
|
|
9
|
+
|---|---|---|---|
|
|
10
|
+
| **Server Component** (default) | Server only, at request or build time | `await`, DB, secrets, `fs` | state, effects, event handlers, browser APIs |
|
|
11
|
+
| **Client Component** (`"use client"`) | Server for the first HTML **and** the browser after | state, effects, handlers | secrets (anything it imports ships to the browser) |
|
|
12
|
+
| **Server Action** (`"use server"`) | Server, called from the browser | DB, secrets | trusting its input: it is a public endpoint |
|
|
13
|
+
|
|
14
|
+
## Hydration, step by step
|
|
15
|
+
|
|
16
|
+
1. The server renders the component tree to HTML and streams it.
|
|
17
|
+
2. The browser paints that HTML (fast, not yet interactive).
|
|
18
|
+
3. The JS loads and React **hydrates**: it renders the client components again and expects the
|
|
19
|
+
*same* output to attach handlers to the existing DOM.
|
|
20
|
+
4. If the output differs, React warns (and may discard and re-render the subtree).
|
|
21
|
+
|
|
22
|
+
## What breaks hydration
|
|
23
|
+
|
|
24
|
+
- `Date.now()`, `new Date()` formatting, `Math.random()`, `crypto.randomUUID()` in the render body.
|
|
25
|
+
- `typeof window !== "undefined"` branches that change the markup.
|
|
26
|
+
- Locale/time-zone formatting that differs between server and browser.
|
|
27
|
+
- Invalid nesting (`<div>` inside `<p>`, `<a>` inside `<a>`) that the browser "fixes" before React looks.
|
|
28
|
+
- Reading `localStorage`/`matchMedia` during render.
|
|
29
|
+
|
|
30
|
+
**Fix pattern:** render a stable first output, then update after mount.
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
"use client";
|
|
34
|
+
import { useEffect, useState } from "react";
|
|
35
|
+
|
|
36
|
+
export function LocalTime({ iso }: { iso: string }) {
|
|
37
|
+
const [text, setText] = useState(iso); // same on server and first client render
|
|
38
|
+
useEffect(() => setText(new Date(iso).toLocaleString()), [iso]); // browser-only, after hydration
|
|
39
|
+
return <time dateTime={iso}>{text}</time>;
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
For values that must exist in render and legitimately differ (theme from a cookie), read them on
|
|
44
|
+
the server and pass them down, so both sides agree.
|
|
45
|
+
|
|
46
|
+
## Rules
|
|
47
|
+
|
|
48
|
+
- Keep `"use client"` as deep (as leaf-like) as possible; a client boundary drags its imports into
|
|
49
|
+
the bundle.
|
|
50
|
+
- Pass the client component data, not the secret that produced it.
|
|
51
|
+
- Treat every Server Action and Route Handler as a public API: authenticate, authorize the object
|
|
52
|
+
and validate the input again. See `secure-coding` (the 10 holes, points 5–7).
|
|
53
|
+
- `suppressHydrationWarning` is for a single known-different text node, never a blanket fix.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: no-me-rayes
|
|
3
|
+
description: "Use on EVERY reply and progress update, especially after tool work or a long task: the assistant must report in short bullet points what is done, what it is doing now, what blocks it, and a final summary, each marked with its own emoji. Cuts the wall-of-text answers some models give. NOT rewriting a text to sound human (that is `bro`), NOT a plain-language explanation (that is `eli5`), NOT a session handoff document (that is `handoff`)."
|
|
4
|
+
tags: [no-me-rayes, concise, bullets, status-report, progress, emojis, short-answers]
|
|
5
|
+
recommends: [bro, eli5, handoff]
|
|
6
|
+
profiles: [minimal, core, ui, full]
|
|
7
|
+
origin: damiangil
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# No me rayes
|
|
11
|
+
|
|
12
|
+
Hay modelos que hablan demasiado. El usuario no quiere párrafos: quiere ver de un vistazo qué pasó. Esta skill se aplica **siempre**, en cada respuesta que cuente trabajo, y la forma no se negocia.
|
|
13
|
+
|
|
14
|
+
## Formato obligatorio
|
|
15
|
+
|
|
16
|
+
Cada bloque lleva su emoji y sus viñetas. Una viñeta, una idea, una línea.
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
✅ Hecho
|
|
20
|
+
- Creé `skills/no-me-rayes/SKILL.md`
|
|
21
|
+
- Pasé los tests de la base
|
|
22
|
+
|
|
23
|
+
🔄 Ahora
|
|
24
|
+
- Regenerando el manifest
|
|
25
|
+
|
|
26
|
+
⛔ Bloqueos
|
|
27
|
+
- Falta el token de ngrok en `.env`
|
|
28
|
+
|
|
29
|
+
📌 Resumen
|
|
30
|
+
- La skill ya está en la base; falta regenerar el manifest
|
|
31
|
+
- Necesito el token para seguir con el túnel
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
| Bloque | Emoji | Qué va dentro |
|
|
35
|
+
| --- | --- | --- |
|
|
36
|
+
| Hecho | ✅ | Lo que ya está terminado y comprobado. |
|
|
37
|
+
| Ahora | 🔄 | Lo que haces en este momento. Una cosa, no tu plan entero. |
|
|
38
|
+
| Bloqueos | ⛔ | Lo que te frena y qué necesitas del usuario para seguir. |
|
|
39
|
+
| Resumen | 📌 | Dos o tres viñetas con lo esencial, para quien solo lea esto. |
|
|
40
|
+
|
|
41
|
+
## Reglas
|
|
42
|
+
|
|
43
|
+
1. **Viñetas, nunca párrafos.** Ninguna viñeta pasa de una línea. Si no cabe, se parte en dos viñetas.
|
|
44
|
+
2. **Solo los bloques que tengan algo.** Si no hay bloqueos, no escribas «Bloqueos: ninguno»: omite el bloque. `📌 Resumen` va siempre al final.
|
|
45
|
+
3. **Resumen al cerrar un trabajo largo.** Tras varios pasos o herramientas, `📌 Resumen` es lo que el usuario lee de verdad: que se entienda sin subir.
|
|
46
|
+
4. **Lo hecho es lo comprobado.** No pongas ✅ a algo que no has ejecutado o verificado; va en 🔄 o se dice que no se probó.
|
|
47
|
+
5. **El bloqueo lleva su salida.** Cada ⛔ dice qué hace falta y de quién, no solo que algo falla.
|
|
48
|
+
6. **Sin relleno.** Nada de «Claro, voy a…», ni de repetir lo que ya se vio en la herramienta, ni de cerrar con un párrafo de cortesía.
|
|
49
|
+
7. **Código, rutas y comandos van exactos**, entre comillas inversas; no se resumen ni se parafrasean.
|
|
50
|
+
8. **Una pregunta de una frase o una respuesta de una línea** no necesita los bloques: responde en una línea. Los bloques son para contar trabajo.
|
|
51
|
+
|
|
52
|
+
## Cómo convive con el resto
|
|
53
|
+
|
|
54
|
+
- **`orient`** cierra cada turno con su bloque-brújula (📍 ✅ 🧭 ➡️). Esta skill manda sobre **el cuerpo** de la respuesta; la brújula va después, sin repetir lo que ya dijo `✅ Hecho`.
|
|
55
|
+
- **`bro`** reescribe un texto para que suene humano; **`eli5`** explica sin jerga. Si el usuario los pide, mandan ellos sobre el contenido; el formato de viñetas se mantiene.
|
|
56
|
+
- **`handoff`** genera un documento de traspaso para otro agente; esto es el parte del turno, no ese documento.
|
|
57
|
+
|
|
58
|
+
## Hecho cuando
|
|
59
|
+
|
|
60
|
+
La respuesta se entiende leyendo solo los emojis y la primera palabra de cada viñeta.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
skill: no-me-rayes
|
|
2
|
+
|
|
3
|
+
should_trigger:
|
|
4
|
+
- prompt: "Hablas demasiado, dime solo qué has hecho."
|
|
5
|
+
why: "Disparador directo de no-me-rayes."
|
|
6
|
+
- prompt: "No me rayes con párrafos, ponlo en viñetas."
|
|
7
|
+
why: "Disparador directo de no-me-rayes."
|
|
8
|
+
- prompt: "Dame un parte de cómo va la tarea: qué está hecho, qué haces ahora y qué te bloquea."
|
|
9
|
+
why: "Disparador directo de no-me-rayes."
|
|
10
|
+
- prompt: "Acabas de tocar siete archivos. Resúmelo en viñetas con emojis."
|
|
11
|
+
why: "Disparador directo de no-me-rayes."
|
|
12
|
+
- prompt: "Your answers are too long; give me done, doing and blocked as short bullets."
|
|
13
|
+
why: "Disparador directo de no-me-rayes."
|
|
14
|
+
|
|
15
|
+
should_not_trigger:
|
|
16
|
+
- prompt: "Reescribe este correo para que suene más natural y humano."
|
|
17
|
+
route_to: "bro"
|
|
18
|
+
why: "Reescribir un texto para que suene humano es el trabajo de bro, no de no-me-rayes."
|
|
19
|
+
- prompt: "Explícame qué es un túnel como si tuviera cinco años."
|
|
20
|
+
route_to: "eli5"
|
|
21
|
+
why: "Explicar sin jerga es el trabajo de eli5, no de no-me-rayes."
|
|
22
|
+
- prompt: "Prepara un documento de traspaso para que otro agente continúe esta conversación."
|
|
23
|
+
route_to: "handoff"
|
|
24
|
+
why: "El documento de traspaso entre agentes es el trabajo de handoff, no de no-me-rayes."
|
|
25
|
+
- prompt: "Haz una retrospectiva de esta sesión y dime qué cambiar en el entorno del agente."
|
|
26
|
+
route_to: "retro"
|
|
27
|
+
why: "La retrospectiva de una sesión es el trabajo de retro, no de no-me-rayes."
|
|
28
|
+
|
|
29
|
+
capability:
|
|
30
|
+
- scenario: "El agente acaba de hacer varios cambios y debe contárselo al usuario."
|
|
31
|
+
must_include:
|
|
32
|
+
- "✅"
|
|
33
|
+
- "📌"
|
package/skills/react/SKILL.md
CHANGED
|
@@ -36,6 +36,8 @@ Adjacent jobs route out: the type system itself (generics, discriminated unions,
|
|
|
36
36
|
|
|
37
37
|
## Component & state architecture
|
|
38
38
|
|
|
39
|
+
The five words behind most front-end bugs (component, state, hooks, rendering, hydration) and a symptom → cause table: `references/mental-model.md`.
|
|
40
|
+
|
|
39
41
|
- **Colocate state** next to where it's used; only **lift** when two siblings must share it. Lifting earlier than needed is the #1 cause of re-render spread.
|
|
40
42
|
- **Derive, don't duplicate.** If a value is computable from props/state, compute it in render — never mirror it into another `useState` synced by an effect.
|
|
41
43
|
- **Context for low-frequency, wide values** (theme, current user, locale). It re-renders every consumer on every change.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# The front-end mental model — five words that explain most bugs
|
|
2
|
+
|
|
3
|
+
Frameworks change every few months; these five ideas do not. When something on screen is wrong,
|
|
4
|
+
find which of the five is misplaced before touching code.
|
|
5
|
+
|
|
6
|
+
| Word | What it is | The mistake it explains |
|
|
7
|
+
|---|---|---|
|
|
8
|
+
| **Component** | A function that takes props and returns UI. A boundary, not a file. | One giant component that fetches, formats and renders: nothing reusable, everything re-renders. |
|
|
9
|
+
| **State** | Data that changes over time and that the screen must reflect. | State copied from props, or derived values stored (`fullName` in `useState`) and left to drift. |
|
|
10
|
+
| **Hooks** | The way a function component remembers (`useState`) or reaches outside itself (`useEffect`). | Effects used to *compute* things (derive in render instead), missing/extra dependencies, hooks called in conditions. |
|
|
11
|
+
| **Rendering** | Running your component to produce a description of the UI; React diffs it and updates the DOM. | Thinking render is a one-off: it runs on every state/prop change, so it must be pure and cheap. |
|
|
12
|
+
| **Hydration** | In SSR/SSG, the server sends HTML; the browser then attaches React to it so it becomes interactive. | Server and client producing different output (`Date.now()`, `Math.random()`, `window`, locale formatting): hydration mismatch. |
|
|
13
|
+
|
|
14
|
+
## Rules that follow
|
|
15
|
+
|
|
16
|
+
- **State** goes to the outermost place that still needs it and no further (URL → server → shared
|
|
17
|
+
parent → component). See [`../SKILL.md`](../SKILL.md) and `ui-engineering`.
|
|
18
|
+
- **Derive, don't mirror.** If it can be computed from props/state during render, compute it there.
|
|
19
|
+
- **Render is pure.** No fetches, timers, `localStorage`, random or time reads in the body. Those
|
|
20
|
+
go in event handlers or effects.
|
|
21
|
+
- **An effect is for synchronizing with something outside React** (a subscription, the DOM, a
|
|
22
|
+
network call). If you are using it to set state from other state, delete it.
|
|
23
|
+
- **Hydration needs identical first output.** Anything that differs between server and browser
|
|
24
|
+
renders after mount (`useEffect` sets it) or is marked with `suppressHydrationWarning` only for
|
|
25
|
+
genuinely unavoidable text (a timestamp). Never use that flag to silence a real mismatch.
|
|
26
|
+
- **Server vs client boundary** (frameworks with server components): data and secrets stay on the
|
|
27
|
+
server side; the client component gets only what it needs. A secret read in a client component
|
|
28
|
+
is public. See `secure-coding` hole 3 and 6.
|
|
29
|
+
|
|
30
|
+
## Quick diagnosis
|
|
31
|
+
|
|
32
|
+
| Symptom | Look first at |
|
|
33
|
+
|---|---|
|
|
34
|
+
| "Text content does not match server-rendered HTML" | Hydration: a non-deterministic value in the first render |
|
|
35
|
+
| Value is one step behind / stale in a handler | State: closure over an old value; use the functional update or derive it |
|
|
36
|
+
| Infinite re-render loop | Hooks: an effect that sets state it depends on |
|
|
37
|
+
| Whole tree re-renders on every keystroke | State: it lives too high; colocate it or select a narrow slice |
|
|
38
|
+
| Works on reload, breaks on navigation (or reverse) | State: it should be in the URL, or an effect ran once too often |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: secure-coding
|
|
3
|
-
description: "Use when securing application code: threat-modeling a feature, security-reviewing a diff, hardening auth/authz, secrets, CORS/CSP, or fixing OWASP-class bugs (access control, injection, SSRF, supply chain) in FastAPI, Next.js, Go or Flutter. NOT running the scanners (that is security-scan), NOT agent prompt-injection guardrails (that is agent-safety)."
|
|
3
|
+
description: "Use when securing application code: threat-modeling a feature, security-reviewing a diff, hardening auth/authz, secrets, CORS/CSP, running the pre-publish checklist (rate limiting, RLS, server-side validation) before shipping an AI-built project, or fixing OWASP-class bugs (access control, injection, SSRF, supply chain) in FastAPI, Next.js, Go or Flutter. NOT running the scanners (that is security-scan), NOT agent prompt-injection guardrails (that is agent-safety)."
|
|
4
4
|
tags: [security, owasp, stride, auth, review]
|
|
5
5
|
recommends: [deployment]
|
|
6
6
|
origin: risco
|
|
@@ -291,6 +291,15 @@ export default { async headers() { return [{ source: "/:path*", headers }]; } };
|
|
|
291
291
|
|
|
292
292
|
Full runbook: `references/secrets-and-supply-chain.md`.
|
|
293
293
|
|
|
294
|
+
## Before publishing — the 10 holes
|
|
295
|
+
|
|
296
|
+
Anything built fast with AI, before it goes public and again before each important launch: rate
|
|
297
|
+
limiting, keys out of the code, production secrets in the platform, per-IP limits, validated and
|
|
298
|
+
parameterized inputs, **validation on the server (the browser's is UX)**, RLS so each user sees only
|
|
299
|
+
their data, hashed passwords and encrypted data, sessions that expire, CORS with only your domain.
|
|
300
|
+
Each point has a concrete proof that it is closed, never "looks fine": `references/pre-publish.md`.
|
|
301
|
+
It is a starting point, not an audit; the audit is [`hardening`](../hardening/SKILL.md).
|
|
302
|
+
|
|
294
303
|
## Anti-patterns
|
|
295
304
|
|
|
296
305
|
| What gets said | Reality |
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Before publishing — the 10 holes
|
|
2
|
+
|
|
3
|
+
A project built fast with AI ships the same ten holes again and again. This is a starting
|
|
4
|
+
point, **not an audit** (the audit is [`hardening`](../../hardening/SKILL.md)). Run it before
|
|
5
|
+
publishing and again before every important launch, about once a month.
|
|
6
|
+
|
|
7
|
+
For each point: what goes wrong, how to **prove** it is closed (a command, a request, a query —
|
|
8
|
+
never "looks fine"), and where the long version lives.
|
|
9
|
+
|
|
10
|
+
| # | Hole | Prove it is closed |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| 1 | **Rate limiting** | Fire 20–50 requests in a few seconds at login, OTP, signup, search and any endpoint that costs money (LLM, email, SMS). Expect `429` well before the end. |
|
|
13
|
+
| 2 | **Keys out of the code** | `gitleaks dir . --redact`; `git log -p -S"sk-" --all` for the history; `grep -rn "process.env" src` only reads names, never literals. `.env` is in `.gitignore` and not in `git ls-files`. |
|
|
14
|
+
| 3 | **Production secrets in the platform** | The values live in Vercel / Supabase / GitHub Actions secrets, not in the repo or in a chat. Only `NEXT_PUBLIC_*` (or the framework's public prefix) reaches the browser: check that no secret carries it. |
|
|
15
|
+
| 4 | **Limits per IP (and per identity)** | The limiter keys on IP **and** on user/session. Behind a proxy, it reads the real client IP (trusted `X-Forwarded-For` hop), not the proxy's. In-memory counters break with more than one replica: use Redis/KV. |
|
|
16
|
+
| 5 | **Validated inputs, parameterized queries** | Every body, query and param passes a schema (Zod `.strict()`, Pydantic, validator) at the boundary. No string-built SQL: `grep -rnE "(query|execute)\(.*(\+|\\$\{)"`. Send `'; --` and `<script>` and see a `400`, not a `500`. |
|
|
17
|
+
| 6 | **Validation on the server** | The browser validating is UX. Re-send the request by hand (`curl`, DevTools "Copy as cURL") with the field the form would have blocked. The server must refuse it. Server Actions and API routes are public. |
|
|
18
|
+
| 7 | **RLS: each user sees only their data** | Every table exposed to the client has RLS **on** and a policy per operation. Log in as user A, request user B's row id: expect empty/`403`. `service_role` never ships to the browser. |
|
|
19
|
+
| 8 | **Passwords hashed, data encrypted** | Argon2id (or bcrypt cost ≥ 12), never SHA-256/MD5, never plain. HTTPS only (HSTS). Sensitive columns (tokens, ids, health/payment data) encrypted at rest, and never written to logs. |
|
|
20
|
+
| 9 | **Sessions that expire** | Short-lived access token, refresh rotation, `HttpOnly` + `Secure` + `SameSite` cookie, logout invalidates server-side. Check: a token from yesterday is rejected. |
|
|
21
|
+
| 10 | **CORS only with your domain** | `Access-Control-Allow-Origin` is an explicit allowlist, never `*` with credentials. Check: `curl -H "Origin: https://evil.example" -I <api>` must not echo that origin back. |
|
|
22
|
+
|
|
23
|
+
## The connection map (what each side may be trusted with)
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
Browser ──request──▶ Server ──query──▶ Database
|
|
27
|
+
│ validated here │ validate AGAIN here │ RLS decides here
|
|
28
|
+
└─ UX only └─ the real gate └─ last line of defence
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
An attacker never uses your browser: they replay or forge the request. Every check that lives
|
|
32
|
+
only in the left box is decoration. Trust nothing that crossed the network; re-check identity,
|
|
33
|
+
ownership and shape at the server, and let the database refuse what the server forgot.
|
|
34
|
+
|
|
35
|
+
## How to use it in a task
|
|
36
|
+
|
|
37
|
+
- **Writing code** that touches auth, an endpoint, a table or a secret: name which of the ten the
|
|
38
|
+
change affects and close it in the same change, with the proof above.
|
|
39
|
+
- **Reviewing a diff** (`code-review`): any new route, table, env var or form must show its
|
|
40
|
+
matching rows. A route with no rate limit and no server validation is a finding, not a nit.
|
|
41
|
+
- **Specifying a feature** (`to-spec`): the "Security" decisions section lists the rows that apply
|
|
42
|
+
and the ones that explicitly do not.
|
|
43
|
+
- **Found a hole:** rotate the credential first, then fix the code, then add the test that fails
|
|
44
|
+
without the fix.
|
|
45
|
+
|
|
46
|
+
Detail per topic: [`owasp-by-stack.md`](owasp-by-stack.md), [`authn-authz.md`](authn-authz.md),
|
|
47
|
+
[`secrets-and-supply-chain.md`](secrets-and-supply-chain.md).
|
package/skills/to-spec/SKILL.md
CHANGED
|
@@ -61,6 +61,13 @@ NO incluyas rutas de archivo concretas ni snippets de código. Pueden quedar obs
|
|
|
61
61
|
|
|
62
62
|
Excepción: si un prototipo produjo un snippet que codifica una decisión con más precisión que la prosa (máquina de estados, reducer, schema, forma de un tipo), inclúyelo dentro de la decisión correspondiente y anota brevemente que salió de un prototipo. Recórtalo a las partes ricas en decisión — no una demo funcional, solo lo importante.
|
|
63
63
|
|
|
64
|
+
## Decisiones de seguridad y de front
|
|
65
|
+
|
|
66
|
+
Solo si la feature toca autenticación, un endpoint, una tabla, un secreto o una pantalla. Si no toca nada de eso, escribe «No aplica» y por qué.
|
|
67
|
+
|
|
68
|
+
- **Seguridad.** De los 10 puntos de `secure-coding` (`references/pre-publish.md`: rate limiting, claves fuera del código, secretos de producción, límites por IP, entradas validadas, validación en el servidor, RLS, hash y cifrado, sesiones que vencen, CORS), anota los que aplican a esta feature y los que quedan fuera a propósito. Cada uno que aplique se convierte en una historia de usuario o en un criterio de aceptación comprobable.
|
|
69
|
+
- **Front.** Dónde vive el estado de cada pieza nueva (URL, servidor, padre compartido o componente), qué es componente de servidor y qué de cliente, y qué primer render debe ser idéntico en servidor y navegador (hidratación). Detalle en `react` y `nextjs` (`references/mental-model.md` y `references/rendering-hydration.md`).
|
|
70
|
+
|
|
64
71
|
## Decisiones de testing
|
|
65
72
|
|
|
66
73
|
Una lista de las decisiones de testing tomadas. Incluye:
|
package/targets/claude.js
CHANGED
|
@@ -10,11 +10,17 @@ const HERE = dirname(fileURLToPath(import.meta.url));
|
|
|
10
10
|
const SHELL_TOOLS = 'Bash|PowerShell';
|
|
11
11
|
|
|
12
12
|
// Mods de la terminal de Claude Code que el harness deja activados en cada proyecto.
|
|
13
|
+
// Los cuatro `@harness-mods` viven en este mismo repo (`mods/plugins/`, catálogo de los mods en
|
|
14
|
+
// la raíz del repo): context-bar, prompt-enhancer, modelo-justo y where-am-i.
|
|
13
15
|
// `cache-tax` mantiene caliente la caché del prompt en las pausas, y eso gasta tokens.
|
|
14
16
|
export const CLAUDE_CODE_MODS = Object.freeze([
|
|
15
17
|
{ id: 'skins@hellosverre-mods', marketplace: 'hellosverre-mods', repo: 'hellosverre/claude-skins' },
|
|
16
18
|
{ id: 'savvy-progress@claude-kit', marketplace: 'claude-kit', repo: 'johnnyvizz/claude-kit' },
|
|
17
19
|
{ id: 'cache-tax@claude-code-mods', marketplace: 'claude-code-mods', repo: 'karanb192/claude-code-mods' },
|
|
20
|
+
{ id: 'context-bar@harness-mods', marketplace: 'harness-mods', repo: 'damiangilgonzalez1995/rsc-harness' },
|
|
21
|
+
{ id: 'prompt-enhancer@harness-mods', marketplace: 'harness-mods', repo: 'damiangilgonzalez1995/rsc-harness' },
|
|
22
|
+
{ id: 'modelo-justo@harness-mods', marketplace: 'harness-mods', repo: 'damiangilgonzalez1995/rsc-harness' },
|
|
23
|
+
{ id: 'where-am-i@harness-mods', marketplace: 'harness-mods', repo: 'damiangilgonzalez1995/rsc-harness' },
|
|
18
24
|
]);
|
|
19
25
|
|
|
20
26
|
export function writeSkill(id, fromDir, toPath) {
|
|
@@ -43,7 +43,7 @@ const SEMVER = /^\d+\.\d+\.\d+(?:-[0-9a-z.-]+)?$/i;
|
|
|
43
43
|
* nothing checks is just drift with a head start.
|
|
44
44
|
*/
|
|
45
45
|
export const PROJECT_OPT_OUTS = [
|
|
46
|
-
'audit', 'claudemd-check', 'danger-guard', 'feature-gate', 'gitmoji', 'knowledge-sync', 'ship-guard', 'trunk-guard', 'trunk-open', 'worktree-cleanup', 'worktree-isolation',
|
|
46
|
+
'audit', 'claudemd-check', 'danger-guard', 'feature-gate', 'gitmoji', 'knowledge-sync', 'ship-guard', 'stack-hints', 'trunk-guard', 'trunk-open', 'worktree-cleanup', 'worktree-isolation',
|
|
47
47
|
];
|
|
48
48
|
|
|
49
49
|
/**
|
package/targets/opt-outs.js
CHANGED
|
@@ -24,6 +24,7 @@ export const PROJECT_OPT_OUTS = [
|
|
|
24
24
|
'gitmoji', // the commit-message convention
|
|
25
25
|
'knowledge-sync', // 01-TOOLS/ + docs/ sync: one person off and the team stops seeing their work
|
|
26
26
|
'ship-guard', // branch/trunk discipline
|
|
27
|
+
'stack-hints', // the session-start reminder that matches the stack (security floor, front-end model)
|
|
27
28
|
'trunk-guard', // «desbloquea main»: the default branch open for the agent, for the whole team
|
|
28
29
|
'trunk-open', // «ramas y PR»: the default branch closed even with nothing that looks complex
|
|
29
30
|
'worktree-cleanup', // the reaper's notice (it only ever names, never acts)
|
|
@@ -166,6 +166,53 @@ Originals are copied, never moved; deleting an emptied folder needs explicit con
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
// Stack hints: a short reminder that matches what THIS project is made of, so it costs nothing
|
|
170
|
+
// where it does not apply. The detail lives in the skills (`secure-coding`, `react`, `nextjs`);
|
|
171
|
+
// these lines are only the part that must be present before anyone asks. Emitted once per session
|
|
172
|
+
// (emitBody de-dups across scopes). Opt out with .rsc/.no-stack-hints.
|
|
173
|
+
function readText(...p) { try { return readFileSync(join(root, ...p), 'utf8'); } catch { return ''; } }
|
|
174
|
+
function stackOf() {
|
|
175
|
+
const pkg = readText('package.json');
|
|
176
|
+
const py = readText('pyproject.toml') + readText('requirements.txt');
|
|
177
|
+
const dep = (re) => re.test(pkg);
|
|
178
|
+
const front = dep(/"(react|preact|next|vue|nuxt|svelte|@sveltejs\/kit|solid-js|astro)"/);
|
|
179
|
+
const back = dep(/"(express|fastify|hono|koa|@nestjs\/core|next|@supabase\/supabase-js|prisma|@prisma\/client|drizzle-orm|firebase)"/)
|
|
180
|
+
|| /fastapi|django|flask/i.test(py) || has('go.mod') || has('supabase')
|
|
181
|
+
|| has('.env') || has('.env.local') || has('.env.example') || has('app', 'api') || has('pages', 'api');
|
|
182
|
+
return { front, back };
|
|
183
|
+
}
|
|
184
|
+
const skillIn = (id) => [root, homedir()].some((r) => existsSync(join(r, '.claude', 'skills', id, 'SKILL.md')));
|
|
185
|
+
if (emitBody && !has('.rsc', '.no-stack-hints')) {
|
|
186
|
+
const { front, back } = stackOf();
|
|
187
|
+
if (back) {
|
|
188
|
+
process.stdout.write(`
|
|
189
|
+
===== rsc security floor =====
|
|
190
|
+
This project has a backend, an API or secrets. Before shipping, and in any change that touches auth,
|
|
191
|
+
an endpoint, a table or a key, close these ten and PROVE each one (a request, a query, a command):
|
|
192
|
+
rate limiting · keys out of the code (.env) · production secrets in the platform (Vercel, Supabase,
|
|
193
|
+
GitHub) · limits per IP and per identity · validated inputs + parameterized queries · validation on
|
|
194
|
+
the SERVER (the browser's is UX) · RLS: each user sees only their data · hashed passwords, encrypted
|
|
195
|
+
data · sessions that expire · CORS only with your own domain.
|
|
196
|
+
Browser validates -> server validates too -> database refuses what the server forgot.
|
|
197
|
+
It is a starting point, not an audit.${skillIn('secure-coding') ? ' Detail and proofs: skill `secure-coding`, references/pre-publish.md. Audit: `hardening`.' : ''}
|
|
198
|
+
Opt out with .rsc/.no-stack-hints.
|
|
199
|
+
==============================
|
|
200
|
+
`);
|
|
201
|
+
}
|
|
202
|
+
if (front) {
|
|
203
|
+
process.stdout.write(`
|
|
204
|
+
===== rsc front-end model =====
|
|
205
|
+
When building the front: component (a boundary, not a file) · state (outermost place that still
|
|
206
|
+
needs it: URL, server, shared parent, component; derive, never mirror) · hooks (an effect syncs
|
|
207
|
+
with the outside world, it does not compute) · rendering (pure, runs on every change) · hydration
|
|
208
|
+
(server HTML and first client render must match: no Date.now/Math.random/window in render).
|
|
209
|
+
Secrets and server-only data never go into a client component.${skillIn('react') || skillIn('nextjs') ? ' Detail: skills `react`, `nextjs` (references/mental-model.md, rendering-hydration.md).' : ''}
|
|
210
|
+
Opt out with .rsc/.no-stack-hints.
|
|
211
|
+
===============================
|
|
212
|
+
`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
169
216
|
// Git required: version control is the substrate the SDD chain + ship guard assume.
|
|
170
217
|
// If the project is not under git, push for it once per session. Persist the user's
|
|
171
218
|
// "no" as .rsc/.no-git so the decision lives in a file and we stop re-asking.
|