Guía para cualquier agente de código (Claude Code, OpenCode, Codex…) que trabaje en este repositorio.
Este archivo cubre solo la verificación de documentación de dependencias y las convenciones de
trabajo. El proyecto en sí está descrito en el README.md — con las correcciones verificadas que
se señalan abajo.
Este proyecto tiene disponible el MCP de context7 (https://context7.com/). Antes de proponer código para las dependencias listadas abajo, consulta la documentación de la versión exacta instalada — no la última publicada, no la que recuerdes.
resolve-library-idcon el nombre de la librería.query-docscon el ID resuelto, la versión de la tabla y el tema concreto.- Si la versión exacta no está indexada, usa la minor más cercana por debajo y di explícitamente en la respuesta qué versión consultaste.
Comprobar que está disponible antes de confiar en él: claude mcp list (o opencode mcp list en
OpenCode) → context7 Connected. Si no lo está, dilo en la respuesta y sigue con conocimiento
propio; no finjas haberlo consultado.
IDs resueltos (verificado 2026-07-27):
| Librería | ID a usar | Aviso |
|---|---|---|
| Astro | /withastro/docs |
Fuente rica (6571 snippets), sin pin de versión |
| Astro (pin) | /withastro/astro/astro_6.3.1 |
Misma minor que la instalada (6.3.7) — usable, pero fuente floja (791 snippets) |
| Tailwind CSS | /websites/tailwindcss |
Doc viva de v4, sin pin |
strict. La API que describen suele ser correcta, pero
omiten las guardas de null. 1431e0f sí lo hay: los coge astro check — ver las
comprobaciones, abajo.
| Paquete | Versión | Nota |
|---|---|---|
astro |
6.3.7 | |
@astrojs/vercel |
10.0.7 | Adapter SSR — el import es @astrojs/vercel, no /serverless |
tailwindcss |
4.3.0 | |
@tailwindcss/vite |
4.3.0 | Integración por plugin de Vite (NO @astrojs/tailwind) |
@tailwindcss/typography |
0.5.19 | 🔴 Cargado y sin usar — ver trampas |
sharp |
0.34.5 | scripts/png-to-webp.mjs + astro:assets. Pre-1.0: rompe entre minors |
unist-util-visit |
5.1.0 | Plugin rehype propio en astro.config.mjs |
@types/node |
25.9.1 | |
vite |
7.3.3 | Transitiva de Astro 6. Otros proyectos del propietario van en v5/v6 |
typescript |
6.0.3 | 1431e0f. Pineado a la 6 a propósito: con la 7 astro check muere |
@astrojs/check |
0.9.10 | astro check compruebe de verdad |
zod no lleva fila: hay una copia en .pnpm (4.4.3) pero es transitiva de Astro, con cero
imports en src/. El esquema de colecciones usa el z que reexporta Astro.
| Paquete | Versión | Trampa |
|---|---|---|
astro |
6.3.7 | Es v6: src/content.config.ts va en la raíz de src/, no en src/content/config.ts; colecciones con loaders glob()/file() del Content Layer (la API legacy se eliminó en v6). z desde astro:content está deprecado — la forma v6 es import { z } from 'astro/zod'. Ya presente en src/content.config.ts: señalar, no reescribir de oficio |
tailwindcss |
4.3.0 | Es v4: @import "tailwindcss" + @theme en src/styles/global.css. No hay tailwind.config.js, ni content: [], ni @tailwind base/components/utilities — eso es v3 |
@tailwindcss/typography |
0.5.19 | Se carga con @plugin en global.css pero la clase prose no aparece en ningún archivo (verificado con grep). El estilo del contenido es CSS propio. No lo uses al escribir componentes |
sharp |
0.34.5 | Pre-1.0: la API rompe entre minors. Verifica contra esta versión exacta |
El README.md dice "sin framework de UI ni CSS utilitario". No es exacto: Tailwind 4 está
instalado y activo en el build (@import "tailwindcss" aplica el preflight al render). Medido
sobre el árbol:
- Cero clases utilitarias en todo
src/, y ningún@apply. Ojo al contarlas:dash-gridyhallazgos-grid(src/pages/index.astro) son clases propias, no la utilitygrid. El estilo real es CSS moderno en bloques<style>de cada.astro(variables,color-mix,clamp). - Tokens brand duplicados:
@themedefine--color-brand(sin uso) y:rootdefine--brandcon el mismo hex (~40 usos — es el sistema vivo). Si cambias un color de marca, toca el de:root; y no mezcles ambos sistemas. - El tema oscuro va por clase
.darken<html>(script inline + localStorage), con selectores.darken el CSS — no haydark:utilities ni@custom-variant.
astro.config.mjs fija output: 'server' y ninguna página exporta prerender = true: cada
petición pasa por la función serverless. Es deliberado — el middleware de control de acceso lo
exige — pero tenlo presente: aquí "generar estático" no es la norma, y un cambio que rompa la
función rompe todas las rutas, no una página.
@types/node es 25.9.1 y el runtime es Node 24 (engines.node + .nvmrc). Los tipos
describen APIs que en 24 pueden no existir: verifica contra la doc de Node 24, no contra lo
que permita el autocompletado. No lo "arregles" por iniciativa propia.
pnpm run verify # astro check && astro build — es lo que ejecuta el CI1431e0f (2026-08-25) esta sección decía que
pnpm run build era «todo lo que hay» y que no había typecheck porque el repo no instalaba
typescript ni @astrojs/check. Ya no es cierto: ambos están instalados y pineados, existe
el script verify, y astro check comprueba los .astro de verdad. Se deja escrito que este
repo estuvo un mes con el tsconfig en strict y nada que lo ejecutara — el dato es que la
puerta faltaba, no solo que ahora esté.
Sigue sin haber lint ni tests: no hay eslint ni script test. La cobertura es tipos +
build.
Línea base medida con el árbol limpio:
| Fecha | Comando | Resultado |
|---|---|---|
| 2026-07-27 | pnpm run build |
✅ verde (9 rutas + función de Vercel) — |
| 2026-08-26 | pnpm run verify |
✅ exit 0 — astro check: 15 ficheros, 0 errores, 0 warnings, 6 hints; build completo |
Comprobado además que astro build no escribe en el repo: el árbol sigue limpio después de
verificar. Si tras un cambio verify sigue verde, no lo has roto tú.
package.jsondice"name": "satellite-shepherd"— nombre interno heredado de la plantilla, no el de este proyecto. Señalarlo, no cambiarlo de oficio.- Control de acceso (
src/middleware.ts): en desarrollo se desactiva solo (import.meta.env.DEV); en producción fail-closed — si faltaACCESS_TOKENen el entorno, bloquea todo menos/restrictedy los assets/_astro/y/_image. Si un cambio tuyo "rompe el sitio" en un deploy de prueba, mira primero esto. - Plugin rehype propio en
astro.config.mjs(rehypeFigureCaption, conunist-util-visit): convierte<p><img></p>en<figure><figcaption>. Si una imagen en Markdown no llevaalt, no se genera caption; si el HTML del contenido cambia de forma, el plugin deja de casar. - El token del enlace de desbloqueo está a la vista en
src/pages/restricted.astro— es la demo del patrón, deliberado. No lo trates como un secreto filtrado, pero tampoco lo uses como ejemplo para nada serio.
- context7 sirve para verificar, no para migrar. No apliques cambios de versión ni "modernices" código que funciona sin que se pida explícitamente. En concreto: no propongas quitar Tailwind, ni "activar" el plugin de typography, ni añadir ESLint/TypeScript de oficio.
- Si la doc actual recomienda un patrón distinto al que ya usa el repo, no reescribas: señálalo y sigue la convención existente salvo que el propietario decida lo contrario.
- Activación reactiva y acotada: solo código nuevo o modificado en la tarea en curso. Nunca como barrido ("revisa todo el proyecto contra la doc actual").
- No lo uses para lógica de negocio, refactors o debugging propio — solo para la API de la librería.
- Este repositorio es PÚBLICO. No añadas a este archivo, ni a ningún otro versionado, nombres de otros repositorios del propietario, rutas locales, ni secretos.
- Formato de Markdown: Prettier por defecto. Tablas estilo GitHub-flavored.
-
Verify before asserting, and with whatever consumes it. Never take a file's word about the environment: run the tool that reads it and trigger what it controls. What cannot be checked stays
❓ pending, said out loud.Asking is not enough:
pnpm config getanswered42for a key that does not exist, andtruefor one that changed nothing. -
"Done" means verified by CI, not asserted. What has not passed the gate stays pending, and that is said.
A green on your machine only proves your machine.
-
.env, credentials and real data dumps: neither read without explicit permission, nor committed. What the agent reads enters the conversation, and from there it does not come back..env.exampleis what travels. -
The AI installs and configures nothing on its own: it proposes, the owner decides.
An install or a config change lands in everyone's lockfile and CI, and neither shows in the diff the agent presents.
-
Nothing destructive without a
--dry-runfirst, showing what would be deleted.A
git clean -fdtook three unrecoverable directories. -
The AI commits; the person decides the push. Local commits pile up until the go-ahead, and one go-ahead covers one push, not the next ones.
-
No AI trace in commits or output: no
Co-Authored-By, no "Generated with…".Tools add it by default. History says what changed and why, not with which tool.
-
Conventional Commits, in English:
type(scope): summary, with!for a breaking change. The types:feat·fix·docs·style·refactor·perf·test·build·ci·chore·revert. The body carries only the list of changes and the reason for each — the how is already in the diff.
-
An agent session has no Node auto-switch. The hook lives in the shell profile and a non-interactive session never loads it: the session runs on whatever Node it inherited when it was launched, and
cdinto another project does not change it.Start the session from a terminal already on the repo's version — enter the directory, let fnm/nvm switch, then launch the agent. One session per project.
If that was not done, activate it on every invocation:
fnm use <major>then the command.fnm exec --using=N pnpmdoes not work on Windows —pnpmis a.cmdandfnm execonly launches real executables. -
pnpm, never npm.
npm install leaves a package-lock.json next to pnpm-lock.yaml, and two
installers disagree in silence.
- pnpm settings live in
pnpm-workspace.yaml;.npmrccarries registry and authentication only — from pnpm 11 anything else there is ignored, and pnpm 10 still reads it, so it works today and stops on upgrade. Every repo with dependencies setsminimumReleaseAgethere.
-
State lives in
docs/SESSION.md, written when a task closes — at session close there is no context left — and overwritten: git keeps the history. Nothing the code orgit logalready tells goes in. -
The reasoning lives in
docs/DECISIONS.md, append-only. A decision that changes is not edited: another is appended revising it, and the old one is marked, never deleted. Knowing what was believed is part of the record. -
An exception is declared in the project's
AGENTS.md, with its reason and its scope; failing silently is not an option. Does not apply to security, AI traces or pushing.
- File names, configuration keys and identifiers in English.
- Skills are per project.
npx autoskillsinstalls them into<repo>/.claude/skills/, which is git-ignored and rebuilt likenode_modules;skills-lock.jsonis committed — it carries each skill's source and hash, and it is what makes three machines rebuild the same set. The developer runsautoskills, not the agent —npxdownloads a package, and installing is not the agent's call.
Global skills in ~/.claude/skills/ are the machine's, not the project's.
- Official docs and MCPs are consulted and never silenced, at the
installed version — from the lockfile, not the
^range. Context7 is the one every project uses:resolve-library-id, thenquery-docsat that version. If the MCP does not answer, say so instead of pretending it was consulted.
- When work is reviewed, this is the shape.
architectbefore building;reviewerandsecurityover what was built, read-only;testerto verify. Run them whenever you want, together or on their own.
🔴 Este repo tiene una reparación pendiente, medidas el 2026-08-26 desde
setupy traídas aquí por el comando de propagación, porque un proyecto no recuerda su propio defecto: su agente lee este fichero, no el registro desetup.
skills-lock.jsongitignorado (§4, medido el 2026-08-26)El detalle y el porqué de cada una están en
findings/pending-repairs.mddel reposetup, en la ficha que cada línea cita. Nada de esto se arregla desde aquí automáticamente (ADR-115): se repara a mano, en este repo, con el contexto que el comando no tiene.
Sitio de documentación técnica que publica una auditoría web completa —rendimiento, seguridad, accesibilidad y SEO— sobre una empresa real anonimizada, con el contenido tras un control de acceso por token.
Qué NO es. Sin frontera declarada. Se preguntó al propietario el 2026-08-26, como reacción a trabajo concreto —alojar varias auditorías de varios clientes, con alta y acceso por cliente— y la respuesta fue buena noticia: no delimita nada. La sección se queda vacía a propósito, no por olvido. Una frontera inventada aquí congelaría una decisión que nadie ha tomado.
Los de este proyecto, y van los primeros a propósito: es la sección de mayor retorno y la que casi todo el mundo entierra a media altura.
pnpm install --frozen-lockfile
pnpm run dev # ❓ no verificado: no termina, y ejecutarlo cuelga la sesión
pnpm run build # ✅ verificado 2026-08-26
pnpm run verify # ✅ verificado 2026-08-26, exit 0 — es lo que ejecuta el CINo hay test: el repo no declara ese script y no se inventa uno. La cobertura de este proyecto
es tipos + build, nada más.
🔴 En sesión de agente no hay auto-switch de Node (rule 9). Comprueba node -v contra
.nvmrc (24) y pnpm -v contra packageManager (10.34.1) en cada invocación, aunque casen por
casualidad.
README.md— qué es el proyecto y su estructura.AGENTS.md— este fichero: versiones instaladas, trampas y reglas.docs/DECISIONS.md— por qué está así lo que no se ve en el código.
Todo lo de abajo es tuyo: el comando que actualiza las capas 1 y 2 no lo toca nunca.
src/middleware.ts— el control de acceso, y la pieza más delicada del repo. Fail-closed en producción (:20-23): sinACCESS_TOKENen el entorno bloquea todo menos/restricted,/_astro/y/_image. La cookie esHttpOnly; Secure; SameSite=Laxcon 2 h de vida (:29).src/content/sections/— las 8 secciones de la auditoría, en Markdown, como Content Collection. El esquema está ensrc/content.config.ts, en la raíz desrc/porque es Astro 6.astro.config.mjs— fijaoutput: 'server'y lleva un plugin rehype propio (rehypeFigureCaption): convierte<p><img></p>en<figure><figcaption>. Si el HTML del contenido cambia de forma, el plugin deja de casar en silencio.scripts/png-to-webp.mjs— conversión por lotes de las 19 capturas consharp.
| Síntoma | Causa | Qué hacer |
|---|---|---|
Se propone tailwind.config.js, @apply o utilities |
Tailwind está instalado pero cero clases utilitarias en src/ |
El estilo real es CSS propio en bloques <style>. Ver «El estilo real es CSS propio» |
Se toca --color-brand para cambiar la marca |
Hay dos sistemas de tokens; el vivo es --brand en :root (~40 usos) |
Tocar el de :root, y no mezclar |
Se usa import { z } from 'astro:content' |
Deprecado en Astro 6 | import { z } from 'astro/zod'. Ya está bien en src/content.config.ts: señalar, no reescribir |
Se «arregla» @types/node 25 sobre Node 24 |
Los tipos van por delante del runtime, a propósito | Verificar contra la doc de Node 24, no contra el autocompletado |
| «El sitio se ha roto» tras un cambio | Todo es SSR: ninguna página exporta prerender |
Mirar primero src/middleware.ts |
L2 — estimated on 2026-09-19: token-based access control with fail-closed middleware, HttpOnly cookie, SSR-only; no money or personal data. Re-estimate when: accounts and payments are added.
Areas:
- Authentication, Session →
src/middleware.ts
- 🔴
skills-lock.jsonno se versiona aquí. Incumple la regla de capa 1 que dice «skills-lock.jsonse versiona;.claude/y.agents/se gitignoran y se reconstruyen connpx autoskills, comonode_modules» —citada por su texto y no por su número, porque los números se renumeran—. Motivo: este repositorio es público y su.gitignorefija «AI / agent tooling — nunca al repo público» (.gitignore:27). Sin fecha de caducidad: mientras el repo sea público, la excepción se mantiene. Razonada endocs/DECISIONS.md, ADR-003.⚠️ Esta excepción hay que mantenerla a mano. El generador del arnés solo comprueba los tres ficheros que él escribe, yskills-lock.jsonno es uno: nada la detecta si desaparece de aquí. - No hay CI todavía, así que la regla «hecho significa verificado por CI» aún no se cumple en
este repo. Es deuda con fecha: se cierra copiando el molde, que ya tiene qué invocar
(
pnpm run verify, verde desde el 2026-08-26).
AGENTS.md— cómo se trabaja aquí (este fichero)docs/DECISIONS.md— por qué está así
Cuándo crear el siguiente. El molde está en ~/.claude/reference/templates/
—ruta del usuario, no del proyecto—; se abre al crearlo y el fichero nuevo ya
sale con sus reglas dentro:
| Si… | → | Documento |
|---|---|---|
| se cierra la sesión con trabajo a medias | → | SESSION.md |
| hay tareas que ya no caben en la cabeza | → | TODO.md |
| unos bloques dependen de lo que producen otros | → | ROADMAP.md |
Para algo que no esté en esa lista —un RUNBOOK.md, una migración—, la receta
está en ~/.claude/reference/templates/README.md. Resumida: contesta a una
pregunta que ningún fichero actual contesta, se sabe quién lo lee, y
nace con su regla de poda. Sin las tres, no se crea.
No hay docs/SESSION.md: este repo no arrastra trabajo a medias. Se crea el día que una
sesión se cierre sin cerrar la tarea, con el molde de ~/.claude/reference/templates/.