Imported from nicoarbelaez/portfolio (
AGENTS.md). Install upstream withnpx skills add nicoarbelaez/portfolio. Copyright stays with the author.
AGENTS.md
Guía obligatoria para agentes que trabajan en este repositorio (Astro 6, React 19, i18n, resume/PDF, API GitHub, deploy en Vercel).
Todas las reglas de desarrollo de este documento son mandatorias. Cualquier modificación o nueva implementación debe cumplirlas. Si una instrucción puntual del usuario entra en conflicto con estas normas, advertir antes de proceder.
Reglas de desarrollo (obligatorias)
Objetivo
Todo cambio debe dejar el código en un estado mejor que antes de la modificación, con calidad de producción y prácticas reconocidas por la industria.
Tamaño de archivos
- Ningún archivo debe superar las 250 líneas de código.
- Si un archivo excede este límite, debe evaluarse inmediatamente su refactorización.
- La división del código debe realizarse por responsabilidad, nunca de forma arbitraria.
Arquitectura
- Aplicar principios SOLID, Clean Architecture y Atomic Design cuando corresponda (UI/componentes).
- Diseñar módulos desacoplados, reutilizables y extensibles.
- Favorecer la composición sobre la herencia.
- Evitar el acoplamiento entre módulos.
- Cada módulo debe tener una única responsabilidad.
Stack de referencia en este repo:
- UI / islas: Astro + React (Atomic Design en
componentscuando existan). - Datos remotos: clientes tipados bajo
src/api/(ej. GitHub). - Config / secretos:
astro:env(env.schema+astro:env/server|client), no tipado manual ensrc/env.d.ts. - Contenido local: content collections solo donde aplique (hoy:
experience).
Reutilización
Antes de implementar una nueva solución:
- Verificar si ya existe dentro del proyecto.
- Verificar si la tecnología utilizada ya ofrece dicha funcionalidad (Astro, React, Vite, Vercel, etc.).
- Verificar si existe una librería ampliamente adoptada y mantenida que resuelva el problema.
- Solo desarrollar una implementación propia cuando exista una justificación técnica clara.
Nunca reinventar la rueda.
Refactorización
Toda refactorización debe:
- Mejorar la mantenibilidad.
- Reducir duplicación de código.
- Incrementar la reutilización.
- No modificar el comportamiento funcional (salvo que el cambio lo pida explícitamente).
- Mantener compatibilidad con futuras extensiones.
Calidad del código
No se permiten soluciones temporales ("quick fixes").
Cada cambio debe:
- Analizar el impacto sobre todo el sistema.
- Considerar casos de uso actuales y futuros.
- Resolver la causa raíz del problema.
- Evitar deuda técnica.
Organización del proyecto
Utilizar la estructura recomendada por Astro (src/pages, src/layouts, src/styles, public, etc.).
Features (dominios)
Cada feature vive en src/features/<nombre>/ y debe organizarse por responsabilidad:
src/features/<feature>/
components/
hooks/
types/
constants/
utils/ # opcional
services/ # opcional
schemas/ # opcional
- Un feature no mezcla lógica de otro dominio (ej. nav no define i18n; i18n no define secciones de nav).
- Prohibido nombrar módulos como
index.ts/index.tsxsalvo un barrel explícito y justificado. Hoy no usar barrels: importar siempre desde el archivo concreto (…/components/FloatingNav,…/types/nav, etc.). - Carpetas vacías se crean cuando el dominio las necesite; no inventar archivos placeholder sin uso.
Shared (cross-cutting)
Lo reutilizable por más de un feature vive fuera de features/:
| Ruta | Uso |
|---|---|
src/components/ |
UI compartida (shadcn, animate-ui, átomos) |
src/components/ui/decorated-text.tsx |
Texto con marcas (highlight/underline); estilos en constants/text-decorators |
src/components/sections/ |
Secciones de página (Hero, Experience, …) |
src/components/pages/ |
Composición de página (evita duplicar en/es) |
src/hooks/ |
Hooks compartidos |
src/lib/ |
Utilidades de bajo nivel (cn, etc.) |
src/utils/ |
Helpers compartidos |
src/types/ |
Tipos compartidos entre dominios |
src/constants/ |
Constantes de sistema (identidad, links) |
src/api/ |
Clientes HTTP / integraciones |
src/i18n/ |
Módulo de internacionalización |
Dependencias: features/* → shared / i18n / api. Nunca al revés (shared no importa features).
Tipado
- Todo el código debe estar completamente tipado.
- Prohibido usar
anyen cualquier forma (: any,as any, genéricosany,Record<string, any>, etc.). - Prohibido silenciar
@typescript-eslint/no-explicit-anyconeslint-disable,eslint-disable-next-lineu otras directivas. Corregir el tipo; no ocultar el error. - Preferir tipos específicos, interfaces, genéricos y
unknown+ narrowing en boundaries. - Validar entradas con esquemas tipados (Zod u equivalente) en frontend y backend/endpoints.
- TypeScript (
noImplicitAny+strict) trata el tipado implícito incorrecto como error. - ESLint trata
anyexplícito como error y prohíbe desactivar@typescript-eslint/no-explicit-any. - Imports y variables no usadas: warning (ESLint
unused-imports; Astro/TS check).
Constantes
No se permiten valores mágicos.
Todo número, string, expresión regular, ruta, clave, nombre de evento o configuración debe centralizarse en constantes o archivos de configuración (src/constants/, schema de astro.config, etc.).
Validación
Toda entrada de datos debe validarse.
- Usar esquemas tipados (Zod u equivalente) en APIs, forms y boundaries.
- Nunca confiar en datos provenientes del cliente.
- Content collections: schemas Zod en
src/content.config.ts. - Env:
envFieldenastro.configconvalidateSecretscuando aplique.
Base de datos
Cuando el proyecto incorpore persistencia:
- Toda interacción con la base de datos debe realizarse mediante Prisma ORM.
- No realizar consultas SQL directas salvo necesidad técnica documentada.
Hoy el portafolio no usa DB propia; al introducirla, esta regla aplica de inmediato.
Auditoría y observabilidad
Toda operación crítica debe poder auditarse.
Registrar como mínimo (logs estructurados, útiles para diagnóstico):
- errores
- operaciones importantes
- autenticación / autorización (si existen)
- cambios de estado
- operaciones sobre base de datos (cuando corresponda)
En este repo: errores de APIs externas (GitHub, resume) deben propagarse con contexto (status, recurso, mensaje), no tragarse en silencio.
Testing
Las implementaciones deben diseñarse para ser testeables.
- Evitar dependencias ocultas y alto acoplamiento.
- Preferir funciones puras, inyección de dependencias y boundaries claros (
api/services/ UI).
Dependencias
Antes de agregar una dependencia nueva, evaluar:
- mantenimiento
- popularidad / comunidad
- licenciamiento
- seguridad
- rendimiento
- compatibilidad con el proyecto
Preferir librerías ampliamente utilizadas por la industria. Justificar en el PR/commit si se añade algo nuevo.
Rendimiento
Toda implementación debe considerar:
- rendimiento
- escalabilidad
- mantenibilidad
- legibilidad
- extensibilidad
No sacrificar la arquitectura por una optimización prematura. En Astro: fetch en paralelo cuando no hay dependencias, secretos solo en servidor, evitar JS de cliente innecesario.
Documentación
- Las decisiones arquitectónicas importantes deben quedar documentadas (este archivo, comentarios de módulo o PR).
- APIs, componentes reutilizables y módulos públicos deben tener documentación suficiente para mantenerlos (JSDoc breve en exports públicos).
Checklist previo a dar por cerrado un cambio
- ¿Algún archivo supera 250 líneas? → refactorizar.
- ¿Se reutilizó lo existente / el framework / una lib madura antes de inventar?
- ¿Tipado completo, sin
anyy sineslint-disablede@typescript-eslint/no-explicit-any? - ¿Sin valores mágicos?
- ¿Entradas validadas en boundaries?
- ¿Errores críticos con contexto útil?
- ¿El código quedó más claro y extensible que antes?
Workflow de adaptación de CV
Caso de uso principal cuando el agente recibe una oferta de trabajo o texto de vacante. El CV vive en resume/cv.yaml y se genera vía RenderCV (pnpm generate:resume / scripts en package.json).
Propósito
- Extraer requisitos clave (skills, tecnologías, responsabilidades, seniority, industria).
- Adaptar
resume/cv.yamldestacando experiencia, proyectos y certificaciones relevantes. - Validar el YAML / render antes de guardar.
- Recordar: cambios mergeados que regeneran el PDF deben validarse localmente cuando sea posible.
Reglas inviolables del CV:
- Nunca fabricar experiencia, fechas, métricas o tecnologías que no aparezcan en el YAML actual o en las fuentes de verdad.
- Mantener el idioma del CV en español (
locale.language: spanish). - Preservar la estructura YAML existente (claves, orden de
sections, fechasYYYY-MM).
Enfoque narrativo
El CV responde, en orden: qué soy capaz de hacer, qué he logrado, cómo lo logré. No es un inventario técnico.
perfil: capacidades de alto nivel + dominio. Evitar listas de tecnologías.experiencia_laboral/proyectos: logro concreto + cómo; tecnologías al final o enTecnologías:.habilidades_tecnicas: agrupadas, sin niveles ni años por tech.certificados: listar todos; reordenar por relevancia, no eliminar.educacion/idiomas: intactos salvo cambio real.
Si un bullet solo lista tecnologías sin logro, reescribirlo o mover la tech a Tecnologías:.
Skills
Si no están registrados como skills activos, leer los SKILL.md directamente:
.agents/skills/resume-tailor/SKILL.md.agents/skills/cv-builder/SKILL.md/.claude/skills/cv-builder/SKILL.md
Flujo: resume-tailor decide qué; cv-builder valida cómo en YAML.
Fuentes de verdad
resume/cv.yaml— CV canónico.src/content/experience/{es,en}/*.md— experiencia extendida (Zod ensrc/content.config.ts).
Si una oferta menciona una tecnología, buscar evidencia real ahí antes de incluirla.
Adaptación por sección
| Sección | Adaptación |
|---|---|
perfil |
Resumen 1–3 líneas con keywords y seniority. |
experiencia_laboral |
Reordenar + highlights cuantificados; no eliminar roles. |
proyectos |
Reordenar/reescribir highlights ya presentes; no inventar. |
habilidades_tecnicas |
Primer bullet = stack principal de la oferta. |
certificados |
Relevantes primero; no inventar. |
educacion / idiomas |
Normalmente intactos. |
Formato: backticks o **negrita** para keywords ATS; fechas YYYY-MM o YYYY; end_date: 'present' para roles actuales; links [texto](url).
Comandos CV
pnpm generate:resume
# o
python -m rendercv render ./resume/cv.yaml \
--dont-generate-markdown --dont-generate-html --dont-generate-png \
--output-folder ./.tmp/rendercv --pdf-path ./resume.pdf
RenderCV resuelve --pdf-path relativo al directorio del YAML (resume/), no al cwd del repo. Usar ./resume.pdf → resume/resume.pdf. No usar ./resume/resume.pdf (crea resume/resume/resume.pdf y rompe el hash en Vercel).
En Vercel: installCommand crea .venv con uv e instala requirements.txt (evita PEP 668 / pip sobre Python gestionado por uv). generate:resume usa .venv/bin/python si existe.
Flujo paso a paso (CV)
- Recibir oferta (link → fetch, o texto).
- Cargar skills
resume-tailor+cv-builder. - Analizar oferta.
- Leer
resume/cv.yaml(+ experience opcional). - Matchear requisito → evidencia; marcar gaps sin inventar.
- Proponer cambios (tabla: sección, cambio, razón).
- Editar YAML válido.
- Validar render si es posible.
- Reportar resumen.
Commits (CV)
- Conventional Commits con scope
cvcuando aplique. - Un commit por adaptación de CV; no mezclar con UI/API no relacionada.
- No commitear PDFs generados si el pipeline los regenera (
public/resume,resume/*.pdfsegún.gitignore).
Perfil del usuario
- Nicolas Arbelaez Tapias — Full Stack con foco Backend, AI-First y automatización. Cali, Colombia.
- Inglés A2 (técnico). No pasar el CV a inglés salvo petición explícita; si se pide, crear archivo aparte (no sobrescribir el español).
- Si la oferta está claramente fuera de perfil, avisar antes de forzar la adaptación.