claude-code-arcane 1.2.0 → 1.4.0

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 (78) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +5 -2
  3. package/agents/ecommerce/ecommerce-architect.md +60 -0
  4. package/agents/engineering/dotnet-engineer.md +78 -0
  5. package/docs/SKILLS-CATALOG.md +45 -3
  6. package/docs/USER-GUIDE.md +2 -2
  7. package/package.json +1 -1
  8. package/profiles/backend-dotnet.yaml +54 -0
  9. package/profiles/ecommerce.yaml +48 -0
  10. package/profiles/job-hunt.yaml +35 -0
  11. package/profiles/unity-design.yaml +1 -0
  12. package/profiles/unity-dev.yaml +1 -0
  13. package/rules/dotnet-code.md +64 -0
  14. package/skills/cart-checkout/SKILL.md +85 -0
  15. package/skills/cart-checkout/references/checkout-flow-spec.md +50 -0
  16. package/skills/cold-outreach/SKILL.md +65 -0
  17. package/skills/cold-outreach/references/recruiter-playbook.md +65 -0
  18. package/skills/commerce-analytics/SKILL.md +85 -0
  19. package/skills/commerce-analytics/references/ga4-ecommerce-events.md +63 -0
  20. package/skills/commerce-analytics/scripts/ga4_ecommerce_validate.py +134 -0
  21. package/skills/commerce-data-model/SKILL.md +84 -0
  22. package/skills/commerce-data-model/references/data-model-spec.md +79 -0
  23. package/skills/cover-letter/SKILL.md +66 -0
  24. package/skills/cv-ats-export/SKILL.md +64 -0
  25. package/skills/cv-ats-export/scripts/cv_export.py +306 -0
  26. package/skills/cv-tailor/SKILL.md +70 -0
  27. package/skills/cv-tailor/references/ats-keywords.md +46 -0
  28. package/skills/dotnet-architecture/SKILL.md +66 -0
  29. package/skills/dotnet-architecture/references/anti-patterns.md +12 -0
  30. package/skills/dotnet-architecture/references/checklist.md +19 -0
  31. package/skills/dotnet-architecture/references/patterns.md +118 -0
  32. package/skills/dotnet-architecture/references/project-structure.md +78 -0
  33. package/skills/dotnet-best-practices/SKILL.md +76 -0
  34. package/skills/dotnet-best-practices/references/api-design.md +75 -0
  35. package/skills/dotnet-best-practices/references/architecture.md +62 -0
  36. package/skills/dotnet-best-practices/references/async.md +62 -0
  37. package/skills/dotnet-best-practices/references/database.md +69 -0
  38. package/skills/dotnet-best-practices/references/dependency-injection.md +73 -0
  39. package/skills/dotnet-best-practices/references/devops.md +76 -0
  40. package/skills/dotnet-best-practices/references/error-handling.md +72 -0
  41. package/skills/dotnet-best-practices/references/performance.md +63 -0
  42. package/skills/dotnet-best-practices/references/security.md +73 -0
  43. package/skills/dotnet-best-practices/references/testing.md +76 -0
  44. package/skills/dotnet-scaffold/SKILL.md +99 -0
  45. package/skills/install-mcp/SKILL.md +107 -0
  46. package/skills/install-mcp/references/manual-setup.md +92 -0
  47. package/skills/interview-prep/SKILL.md +69 -0
  48. package/skills/interview-prep/references/star-framework.md +42 -0
  49. package/skills/inventory-stock/SKILL.md +86 -0
  50. package/skills/inventory-stock/scripts/restock_forecast.py +173 -0
  51. package/skills/job-hunt/SKILL.md +92 -0
  52. package/skills/job-hunt/references/templates/Aplicacion.md +48 -0
  53. package/skills/job-hunt/references/templates/CV Custom.md +53 -0
  54. package/skills/job-hunt/references/templates/Contacto.md +30 -0
  55. package/skills/job-hunt/references/templates/Dashboard.md +45 -0
  56. package/skills/job-hunt/references/templates/Empresa.md +36 -0
  57. package/skills/job-hunt/references/templates/Entrevista.md +44 -0
  58. package/skills/job-hunt/references/templates/Perfil.md +38 -0
  59. package/skills/job-search/SKILL.md +83 -0
  60. package/skills/job-search/references/scoring-rubric.md +43 -0
  61. package/skills/linkedin-optimize/SKILL.md +79 -0
  62. package/skills/master-profile/SKILL.md +69 -0
  63. package/skills/merchant-feed/SKILL.md +85 -0
  64. package/skills/merchant-feed/references/feed-attribute-map.md +47 -0
  65. package/skills/merchant-feed/scripts/feed_validate.py +140 -0
  66. package/skills/network-map/SKILL.md +61 -0
  67. package/skills/network-map/scripts/network_map.py +109 -0
  68. package/skills/order-lifecycle/SKILL.md +86 -0
  69. package/skills/order-lifecycle/references/order-state-machine.md +53 -0
  70. package/skills/payments-architecture/SKILL.md +80 -0
  71. package/skills/personal-brand/SKILL.md +54 -0
  72. package/skills/personal-brand/references/post-pillars.md +66 -0
  73. package/skills/portfolio-site/SKILL.md +59 -0
  74. package/skills/product-listing/SKILL.md +84 -0
  75. package/skills/promotions-discounts/SKILL.md +80 -0
  76. package/skills/shipping-tax/SKILL.md +85 -0
  77. package/skills/storefront-architecture/SKILL.md +80 -0
  78. package/skills/subscription-billing/SKILL.md +81 -0
@@ -0,0 +1,44 @@
1
+ ---
2
+ tipo: entrevista
3
+ aplicacion:
4
+ empresa:
5
+ ronda:
6
+ fecha: {{date:YYYY-MM-DD}}
7
+ duracion:
8
+ entrevistadores: []
9
+ modalidad:
10
+ ---
11
+
12
+ # {{title}}
13
+
14
+ ## Aplicación
15
+ - [[]]
16
+
17
+ ## Preparación
18
+ - Research de empresa: [[]]
19
+ - Temas a repasar:
20
+ -
21
+ - Preguntas propias a hacer:
22
+ -
23
+
24
+ ## Durante la entrevista
25
+ ### Temas que surgieron
26
+ -
27
+
28
+ ### Preguntas que me hicieron
29
+ -
30
+
31
+ ### Preguntas que hice
32
+ -
33
+
34
+ ## Feedback
35
+ ### Cómo salí (autoevaluación)
36
+
37
+
38
+ ### Señales de ellos
39
+
40
+
41
+ ## Próximo paso
42
+
43
+
44
+ ## Notas post-entrevista
@@ -0,0 +1,38 @@
1
+ ---
2
+ tipo: perfil
3
+ rol_objetivo:
4
+ seniority:
5
+ stack: []
6
+ modalidad: []
7
+ mercado_objetivo: []
8
+ match_score_minimo: 75
9
+ salario_minimo_usd_mes:
10
+ keywords: []
11
+ keywords_excluir: []
12
+ regla_seniority:
13
+ fuentes: []
14
+ ---
15
+
16
+ # Perfil — {{title}}
17
+
18
+ ## Resumen
19
+ > 2–3 líneas: quién sos para este rol y qué te hace fuerte.
20
+
21
+ ## Stack principal
22
+ -
23
+
24
+ ## Experiencia destacada para este perfil
25
+ -
26
+
27
+ ## Diferenciales
28
+ -
29
+
30
+ ## Logros cuantificables (para CV)
31
+ > Con número, contexto y resultado. Reusables en CVs y LinkedIn.
32
+ -
33
+
34
+ ## CVs asociados
35
+ -
36
+
37
+ ## Aplicaciones relacionadas
38
+ -
@@ -0,0 +1,83 @@
1
+ ---
2
+ name: job-search
3
+ description: "Find, score and prioritize job openings against your profile, then build a structured 7-day search plan with daily goals. Creates application and company notes in the workspace. Triggers: buscar trabajo, encontrar ofertas, scorear ofertas, plan de busqueda laboral, priorizar postulaciones, job search plan, donde aplicar."
4
+ argument-hint: "[search <query> | score <job-url> | plan]"
5
+ category: "career"
6
+ user-invocable: true
7
+ allowed-tools: Read, Glob, Grep, Write, Edit, WebFetch, WebSearch
8
+ ---
9
+
10
+ # Job Search — Búsqueda, scoring y plan
11
+
12
+ Encontrás ofertas, las **scoreás** contra el perfil del usuario, priorizás, y armás un **plan de búsqueda de 7 días** con objetivos diarios. Alimentás el workspace con notas de aplicación y empresa para que el resto del flujo (`/cv-tailor`, `/cover-letter`, etc.) las consuma.
13
+
14
+ ## Inputs
15
+
16
+ - **Perfil(es) objetivo** (`01-Perfiles/`): rol, seniority, stack, modalidad, mercado, **score mínimo** (default 75), salario mínimo, keywords y keywords a excluir.
17
+ - Fuentes de ofertas que use el usuario (job boards, WeWorkRemotely, LinkedIn, Workable, etc.).
18
+
19
+ ## Modos
20
+
21
+ ### `search <query>` — Encontrar ofertas
22
+ 1. **Sourcing.** Conseguir ofertas frescas que matcheen el perfil (rol + stack + modalidad + mercado). Dos caminos:
23
+ - **Apify MCP (opcional).** Si hay un MCP de Apify conectado, podés usar un actor de scraping de LinkedIn Jobs para traer ofertas estructuradas. Ejemplo de pedido: *"Scrapeá LinkedIn jobs para [rol] posteadas en los últimos 7 días en empresas de 50–5000 empleados; filtrá por match con mi background en [dominio]; devolvé tabla rankeada con empresa, rol, ubicación, salario, fecha de posteo y fit score 1–10 basado en mi resume; marcá el top 10 para aplicar hoy."* Buscá el actor con ToolSearch (`apify`) si el MCP está presente. **⚠️ OBLIGATORIO: antes de invocar Apify, mostrá el warning de abajo y pedí confirmación explícita.**
24
+ - **WebSearch/WebFetch (default recomendado).** Camino sin Apify: buscar en job boards (muchos con feed/API pública: WeWorkRemotely, RemoteOK, etc.) y fetchear los JDs. Es el default seguro y gratis.
25
+
26
+ > ### ⚠️ Warning Apify — mostralo SIEMPRE antes de usar esta parte
27
+ >
28
+ > Antes de correr cualquier actor de Apify (especialmente scraping de LinkedIn), presentá estos puntos al usuario y esperá confirmación explícita. No invoques Apify "en silencio".
29
+ >
30
+ > 1. **No es gratis.** Apify cobra por uso (compute units / por resultado); un scrape grande consume crédito. El tier free es limitado.
31
+ > 2. **Scrapear LinkedIn viola sus Términos de Servicio.** LinkedIn detecta y bloquea scraping activamente y puede **restringir o banear la cuenta**. La legalidad de scrapear datos públicos está en zona gris (caso hiQ vs LinkedIn); el riesgo de ToS/cuenta es real y es del usuario, no de Apify. Preferir actors sobre **job boards públicos** antes que LinkedIn directo; si igual se scrapea LinkedIn, hacerlo de forma consciente y no con una cuenta crítica.
32
+ > 3. **El API token de Apify es sensible.** Autoriza correr actors (y gastar el plan) en nombre del usuario. Mantenerlo seguro; no exponerlo ni commitearlo. (Apify no recolecta conversaciones/tokens y trata a los actors como no confiables: les da un proxy y no les entrega las credenciales — un actor malicioso puede usar las tools habilitadas pero no exfiltrar el token.)
33
+ > 4. **Calidad/estabilidad variable.** Los scrapers de LinkedIn se rompen seguido; los resultados pueden venir incompletos o desactualizados.
34
+ >
35
+ > Si el usuario no confirma, usá el camino WebSearch/WebFetch.
36
+ 2. Para cada oferta candidata: extraer rol, empresa, stack, modalidad, ubicación, rango salarial, link, fecha de cierre.
37
+ 3. Scorear (ver rúbrica) y filtrar por el umbral del perfil.
38
+ 4. Crear nota en `03-Aplicaciones/` (template `Aplicacion`, estado `interesado`, con `score`) + nota en `04-Empresas/` (template `Empresa`) por cada una sobre el umbral.
39
+ 5. Actualizar el `00-Dashboard.md` con las activas por prioridad, marcando el **top 10 para hoy**.
40
+
41
+ ### `score <job-url>` — Scorear una oferta puntual
42
+ 1. WebFetch del JD.
43
+ 2. Aplicar la rúbrica contra el perfil → score 0–100 + breakdown + recomendación (aplicar / borderline / skip).
44
+ 3. Si pasa, crear las notas como arriba.
45
+
46
+ ### `plan` — Plan de búsqueda de 7 días
47
+ Generar un plan accionable con objetivos diarios. Ejemplo de esqueleto (ajustar al estado del usuario):
48
+
49
+ - **Día 1 — Base.** Perfil maestro + perfiles por rol al día; LinkedIn optimizado (`/linkedin-optimize`).
50
+ - **Día 2 — Sourcing.** Buscar y scorear 15–20 ofertas; quedarte con las ≥ umbral.
51
+ - **Día 3 — Research.** Empresas + contactos objetivo de las top.
52
+ - **Día 4 — Aplicaciones tanda 1.** CV custom + cover letter para las 5 de mayor prioridad (`/cv-tailor`, `/cv-ats-export`, `/cover-letter`).
53
+ - **Día 5 — Outreach.** Mensajes a recruiters/hiring managers de las top (`/cold-outreach`).
54
+ - **Día 6 — Aplicaciones tanda 2** + follow-ups de la tanda 1.
55
+ - **Día 7 — Review.** Métricas (aplicadas / respuestas / entrevistas), ajustar perfil/CV según señales, planear próxima semana.
56
+
57
+ ## Rúbrica de scoring
58
+
59
+ Ver `references/scoring-rubric.md`. En resumen, score ponderado 0–100 sobre:
60
+ - Match de stack/skills (peso alto)
61
+ - Seniority correcto (penalizar over/under-qualified)
62
+ - Modalidad y mercado/elegibilidad (remoto, zona horaria, visa)
63
+ - Salario vs mínimo
64
+ - Cultura/etapa según preferencia
65
+ - Señales de calidad de la oferta (claridad, recencia, # aplicantes)
66
+
67
+ Umbral default ≥75 (configurable en el frontmatter del perfil, campo `match_score_minimo`).
68
+
69
+ ## Tracking
70
+
71
+ - Estados de aplicación: `interesado` → `aplicado` → `en proceso` → `entrevista` → `oferta` / `rechazado` / `descartado`.
72
+ - Mantener el `00-Dashboard.md` como vista única: activas por prioridad, próximas entrevistas, qué cierra pronto, a seguir esta semana.
73
+
74
+ ## Reglas
75
+
76
+ - No aplicar a todo: el umbral existe para concentrar esfuerzo donde hay match real.
77
+ - Marcar gaps con honestidad al scorear (no inflar el match).
78
+ - Respetar elegibilidad (visa/zona horaria) — un score alto con bloqueo de elegibilidad no sirve.
79
+ - No guardar datos sensibles de recruiters en remotos sin confirmación.
80
+
81
+ ## Handoff
82
+
83
+ Confirmá (approval) antes de crear notas de aplicación/empresa o tocar el Dashboard. Cuando las ofertas priorizadas están READY, el siguiente paso es `/cv-tailor` sobre las de prioridad alta.
@@ -0,0 +1,43 @@
1
+ # Job Scoring Rubric
2
+
3
+ Score ponderado 0–100 para decidir dónde invertir esfuerzo. El objetivo no es aplicar a todo: es concentrarte en ofertas con match real. Umbral default **≥75** (configurable por perfil en `match_score_minimo`).
4
+
5
+ ## Dimensiones y pesos (default)
6
+
7
+ | Dimensión | Peso | Cómo puntuar |
8
+ |---|---:|---|
9
+ | **Match de stack/skills** | 30 | % de must-haves que cumplís. 30 si cubrís todos los core; baja proporcional. |
10
+ | **Seniority** | 15 | 15 si el nivel encaja. Penalizar over-qualified (aburrimiento/rechazo) y under-qualified (filtro). |
11
+ | **Modalidad + elegibilidad** | 20 | Remoto/híbrido/presencial según preferencia; zona horaria; visa/eligibility. Si hay bloqueo duro de elegibilidad → cap fuerte al score. |
12
+ | **Salario** | 15 | 15 si ≥ tu objetivo; proporcional hasta tu mínimo; 0 si por debajo del mínimo. Si no publican, neutro (≈8) y marcar. |
13
+ | **Empresa/cultura/etapa** | 10 | Encaje con preferencia (startup vs enterprise, producto vs consultora, valores). |
14
+ | **Calidad de la oferta** | 10 | Claridad del JD, recencia (fresca > vieja), pocos aplicantes, proceso definido. |
15
+
16
+ Sumá las dimensiones → score 0–100.
17
+
18
+ ## Ajustes / banderas
19
+
20
+ - **Frase gatillo positiva** (ej. "code-forward", "high autonomy", stack que amás): +2–5 si refuerza tu fit.
21
+ - **Red flag en el JD** (ego, "rockstar", scope imposible, "trabajamos como familia"): −5–10 y nota de cautela.
22
+ - **Cierre inminente:** no cambia el score, pero sube la **prioridad** de acción.
23
+ - **Elegibilidad bloqueada** (visa que no tenés, zona horaria incompatible obligatoria): cap el score a <50 aunque el resto sea perfecto.
24
+
25
+ ## De score a acción
26
+
27
+ | Score | Acción |
28
+ |---|---|
29
+ | **≥85** | Prioridad alta. Aplicar con CV custom + cover letter + outreach. |
30
+ | **75–84** | Aplicar; CV custom sí, outreach si hay contacto fácil. |
31
+ | **60–74** | Borderline. Aplicar solo si hay tiempo o un ángulo fuerte (referido). |
32
+ | **<60** | Skip salvo razón estratégica. |
33
+
34
+ ## Prioridad (distinta del score)
35
+
36
+ `prioridad` en el frontmatter combina score + urgencia + elegibilidad:
37
+ - **alta:** score ≥85, o ≥75 con cierre inminente / referido caliente.
38
+ - **media:** 75–84 sin urgencia.
39
+ - **baja:** borderline o a la espera de validar requisitos.
40
+
41
+ ## Registro
42
+
43
+ Guardá el `score` en el frontmatter de la nota de `03-Aplicaciones/` y reflejá las activas en `00-Dashboard.md` agrupadas por prioridad. Anotá el breakdown si el score fue borderline — ayuda a decidir y a re-evaluar después.
@@ -0,0 +1,79 @@
1
+ ---
2
+ name: linkedin-optimize
3
+ description: "Optimize a LinkedIn profile to attract recruiters and rank in search — headline, About, experience with KPIs, keywords, value proposition and a 30-second pitch. No LinkedIn Premium needed. Triggers: optimizar LinkedIn, mejorar perfil LinkedIn, headline LinkedIn, about LinkedIn, LinkedIn para reclutadores, LinkedIn SEO, pitch profesional."
4
+ argument-hint: "[section | full] (paste your current profile)"
5
+ category: "career"
6
+ user-invocable: true
7
+ allowed-tools: Read, Glob, Grep, Write, Edit
8
+ ---
9
+
10
+ # LinkedIn Optimize — Perfil que atrae oportunidades
11
+
12
+ Optimizás un perfil de LinkedIn para que (1) ranquee en las búsquedas de recruiters y (2) convenza al humano que lo abre. Trabajás contra el **perfil maestro** (`01-Perfiles/`) y lo que el usuario pega de su perfil actual.
13
+
14
+ > **Importante:** Claude no accede a LinkedIn ni edita el perfil directamente. El usuario pega/sube el contenido actual; vos generás el texto optimizado para que lo copie/pegue.
15
+
16
+ ## Cómo traer tu perfil a Claude
17
+
18
+ La forma más completa: en LinkedIn → **Recursos / More → Save to PDF** (exporta el perfil entero) y subí ese PDF a Claude. Alternativa: copiar/pegar headline + About + experiencia. Con el PDF, podés pedir una **auditoría contra JDs reales**:
19
+
20
+ > "Audita mi perfil de LinkedIn (adjunto) contra JDs de [rol] senior en [empresas objetivo]. Encontrá gaps en headline, About y Experience: keywords faltantes, framing de identidad equivocado, credenciales enterradas. Después reescribí headline y About para posicionarme como **builder**, optimizado para la búsqueda de recruiters."
21
+
22
+ **Framing de identidad:** posicionate como alguien que *construye/entrega* (builder), no como una lista de tareas. El headline y el About deben gritar resultados e identidad, no responsabilidades.
23
+
24
+ ## Las 7 áreas de optimización
25
+
26
+ Cubrí estas siete (el usuario puede pedir una con `[section]` o todas con `full`):
27
+
28
+ ### 1. Headline (titular)
29
+ - 220 caracteres. No solo el puesto: **rol + valor + keywords**.
30
+ - Patrón: `{Rol} | {especialidad/stack} | {valor o a quién ayudás}`.
31
+ - Las keywords del headline pesan fuerte en el ranking de búsqueda.
32
+
33
+ ### 2. About (sección "Acerca de")
34
+ - Primera 2–3 líneas son las que se ven sin "ver más": que enganchen.
35
+ - Estructura: gancho → qué hacés y para quién → 2–3 logros con número → stack/keywords → CTA suave.
36
+ - Primera persona, tono humano, escaneable (párrafos cortos o bullets).
37
+
38
+ ### 3. Experiencia con KPIs
39
+ - Cada rol con bullets de **logros cuantificables**, no responsabilidades.
40
+ - Mismo principio que el CV: verbo de acción + métrica + impacto.
41
+ - Incluí keywords de tu industria/rol en los bullets.
42
+
43
+ ### 4. Keywords estratégicas (LinkedIn SEO)
44
+ - Identificá las keywords que los recruiters de tu rol buscan.
45
+ - Distribuilas en headline, About, experiencia, y la sección Skills.
46
+ - Las **Skills** (hasta 50, fijá las 3 top) alimentan el match con búsquedas y endorsements.
47
+
48
+ ### 5. Propuesta de valor única
49
+ - Qué te diferencia: combinación de skills, dominio, resultados. Una frase clara que sintetiza "por qué vos".
50
+
51
+ ### 6. Pitch de 30 segundos
52
+ - Versión hablada de tu propuesta de valor: quién sos, qué hacés/resolvés, qué buscás. Para mensajes, networking y el "contame de vos".
53
+
54
+ ### 7. Review ATS / searchability
55
+ - Foto profesional, banner, URL personalizada, "Open to work" configurado (público o solo-recruiters), ubicación y rol objetivo seteados.
56
+ - Perfil completo = más alcance (LinkedIn premia completitud).
57
+ - Sin gaps inexplicados; títulos consistentes con cómo se busca el rol.
58
+
59
+ ## Proceso
60
+
61
+ 1. Leer el perfil maestro + lo que el usuario pega de su LinkedIn actual.
62
+ 2. Definir el/los **rol(es) objetivo** y sus keywords (reusá `cv-tailor/references/ats-keywords.md` para el método).
63
+ 3. Generar el contenido optimizado por sección (la/s que pida).
64
+ 4. Entregar listo para copiar/pegar + un checklist de la review (área 7).
65
+ 5. Opcional: guardar el output en `01-Perfiles/LinkedIn.md` para versionarlo.
66
+
67
+ ## Idioma
68
+
69
+ LinkedIn en **inglés** si apuntás a roles internacionales (mayor alcance), español si tu mercado es local. Se puede tener el About bilingüe.
70
+
71
+ ## Reglas
72
+
73
+ - No inventar logros ni métricas — todo debe ser defendible.
74
+ - Keywords naturales, no stuffing.
75
+ - Recordar que no se puede acceder/editar LinkedIn: el output es para copiar/pegar.
76
+
77
+ ## Handoff
78
+
79
+ Pedí aprobación (approval) antes de escribir `01-Perfiles/LinkedIn.md`. Cuando el contenido está READY para copiar/pegar, un buen siguiente paso es `/portfolio-site` para alinear el portfolio web.
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: master-profile
3
+ description: "Build and maintain the master professional profile — the single source of truth (experience, skills with levels, projects, education, references, bios) that every CV, LinkedIn profile and portfolio derives from. Triggers: perfil maestro, master resume, cronologia laboral, single source of truth CV, mi experiencia profesional."
4
+ argument-hint: "[build | update | derive <role>]"
5
+ category: "career"
6
+ user-invocable: true
7
+ allowed-tools: Read, Glob, Grep, Write, Edit
8
+ ---
9
+
10
+ # Master Profile — Single Source of Truth
11
+
12
+ Construís y mantenés el **perfil maestro**: el documento del que derivan todos los CVs, el LinkedIn y el portfolio. La regla de oro: **si algo cambia, se cambia acá primero** y de acá se sincroniza al resto.
13
+
14
+ Vive en `01-Perfiles/Perfil Maestro.md` dentro del career workspace. Los perfiles por rol (`Backend.md`, `Frontend.md`, etc.) son **vistas filtradas** del maestro, no fuentes independientes.
15
+
16
+ ## Por qué existe
17
+
18
+ Mantener N CVs sincronizados a mano es la causa #1 de errores (fechas que no coinciden, logros que faltan en una versión). Con un maestro: editás un lado, derivás el resto. `/cv-tailor`, `/linkedin-optimize` y `/portfolio-site` consumen este archivo.
19
+
20
+ ## Estructura del perfil maestro
21
+
22
+ Generá el archivo con estas secciones (todas las que apliquen):
23
+
24
+ 1. **Personal info** — nombre, display name, headline actual, ubicación, email público vs personal, teléfono, LinkedIn, GitHub, portfolio. (El email *público* puede diferir del personal.)
25
+ 2. **Bios** — tres largos: corto (hero/one-liner), medio (2–3 oraciones para "About"), largo (about page completo).
26
+ 3. **Work experience** (más reciente primero) — por cada rol: empresa, período, ubicación/modalidad, producto, stack, manager/referencia, y **bullets de logros con número→contexto→resultado**.
27
+ 4. **Education** — institución, período, foco.
28
+ 5. **Certifications** — nombre, año, estado (completo/in progress).
29
+ 6. **Skills consolidados con nivel** — agrupados (lenguajes, frameworks, infra, tooling) con nivel (Expert/Advanced/Proficient/…) y opcionalmente % para el portfolio.
30
+ 7. **Projects** — tech, rol, highlights, link en vivo.
31
+ 8. **Achievements / highlights** — premios, showcases, hitos.
32
+ 9. **Languages** — idioma + nivel.
33
+ 10. **References** — nombre, rol, relación, contacto.
34
+
35
+ ## Modos
36
+
37
+ ### `build` — Crear el maestro desde cero
38
+ 1. Si no existe el workspace, sugerir `/job-hunt setup` primero.
39
+ 2. Recolectar info por sección — preferí **entrevistar al usuario por bloques** (no un cuestionario gigante). Empezá por experiencia y skills.
40
+ 3. Para cada logro, empujar a la forma **cuantificable**: "¿qué número podés ponerle? ¿comparado con qué? ¿qué resultado tuvo?". Un bullet sin métrica es una oportunidad perdida.
41
+ 4. Escribir `01-Perfiles/Perfil Maestro.md`.
42
+ 5. Sugerir derivar el primer perfil por rol: `/master-profile derive <role>`.
43
+
44
+ ### `update` — Mantener al día
45
+ 1. Leer el maestro actual.
46
+ 2. Aplicar el cambio (nuevo rol, nuevo logro, ascenso, proyecto).
47
+ 3. **Avisar qué derivados quedan desactualizados** (CVs por rol, LinkedIn, portfolio) y ofrecer re-derivarlos.
48
+
49
+ ### `derive <role>` — Vista por rol
50
+ 1. Leer el maestro.
51
+ 2. Crear/actualizar `01-Perfiles/<Role>.md` con el template `Perfil` (ver `Templates/Perfil.md`): filtrar y reordenar la experiencia/skills/proyectos hacia ese rol, definir keywords objetivo, score mínimo y mercado.
52
+ 3. Este perfil por rol es el `perfil_base` que después usa `/cv-tailor`.
53
+
54
+ ## Principios de redacción
55
+
56
+ - **Logros, no responsabilidades.** "Reduje latencia de servidor 25%" > "Encargado del servidor".
57
+ - **Verbos de acción + métrica + impacto.** Owned, shipped, led, reduced, increased, scaled.
58
+ - **Verdad verificable.** Nada que no puedas defender en una entrevista.
59
+ - **Inglés para roles internacionales**, español cuando aplique. El maestro puede tener los valores en inglés (van directo a CV/portfolio) y las meta-notas en español.
60
+
61
+ ## Reglas
62
+
63
+ - Una sola fuente de verdad: no dejar que un CV por rol "evolucione" por fuera del maestro.
64
+ - No inventar logros ni métricas — si el usuario no tiene el número, marcarlo como pendiente, no fabricarlo.
65
+ - Separar email público de personal; no exponer datos sensibles en archivos que vayan a un remoto.
66
+
67
+ ## Handoff
68
+
69
+ Confirmá con el usuario (approval) antes de escribir el perfil maestro o pisar derivados. Cuando el maestro está READY, derivá perfiles por rol y seguí con `/cv-tailor`, `/linkedin-optimize` o `/portfolio-site`.
@@ -0,0 +1,85 @@
1
+ ---
2
+ name: merchant-feed
3
+ description: "Build and validate product feeds for shopping channels — Google Merchant Center and Meta Catalog — including required/recommended attributes, attribute mapping, and feed validation. Includes a feed validator/generator script. Triggers: building a product feed, fixing feed disapprovals, mapping catalog to feed attributes."
4
+ argument-hint: "[validate | generate | map]"
5
+ category: "ecommerce"
6
+ user-invocable: true
7
+ allowed-tools: Read, Glob, Grep, Bash
8
+ ---
9
+
10
+ # Merchant Feed
11
+
12
+ Shopping ads and free listings live or die on feed quality. A clean, complete feed gets products approved and surfaced; a sloppy one gets disapprovals. Map your catalog to channel attributes and validate before upload — platform-agnostic.
13
+
14
+ ## Before Starting
15
+
16
+ Gather: target channel (Google Merchant / Meta Catalog), source of truth (DB export, CSV, platform), product categories, and goal (validate an existing feed, generate one, or map catalog → feed attributes).
17
+
18
+ ## How This Skill Works
19
+
20
+ | Mode | Trigger | Output |
21
+ |------|---------|--------|
22
+ | **Validate** | `validate` | Pass/fail report against required attributes |
23
+ | **Generate** | `generate` | Feed emitted from a source CSV |
24
+ | **Map** | `map` | Catalog field → feed attribute mapping |
25
+
26
+ ---
27
+
28
+ ## Phase 1 — Required Attributes
29
+
30
+ Google Merchant / Meta share a common core. Required for every item:
31
+
32
+ | Attribute | Notes |
33
+ |-----------|-------|
34
+ | `id` | Stable, unique per variant (use SKU) |
35
+ | `title` | Front-load product; ≤150 chars; match landing page |
36
+ | `description` | Plain, accurate; no promo text/caps |
37
+ | `link` | Canonical PDP URL |
38
+ | `image_link` | Main image, meets resolution minimums |
39
+ | `availability` | in_stock / out_of_stock / preorder |
40
+ | `price` | With currency; must match landing page exactly |
41
+ | `brand` | Required unless exempt category |
42
+ | `gtin` / `mpn` | Required where a GTIN exists — improves matching |
43
+ | `condition` | new / refurbished / used |
44
+
45
+ **Rule:** Feed price and availability must **exactly match** the live PDP, or the item is disapproved and the account is penalized.
46
+
47
+ ---
48
+
49
+ ## Phase 2 — Validate / Generate
50
+
51
+ Run the validator on a CSV export:
52
+
53
+ ```bash
54
+ python skills/merchant-feed/scripts/feed_validate.py # demo data
55
+ python skills/merchant-feed/scripts/feed_validate.py feed.csv
56
+ ```
57
+
58
+ It checks every row for required attributes, flags missing/empty values, validates `availability`/`condition` enums and price+currency format, and reports a per-row and summary verdict. For the full attribute reference and category-specific requirements, see [references/feed-attribute-map.md](references/feed-attribute-map.md).
59
+
60
+ ---
61
+
62
+ ## Phase 3 — Recommended Attributes & Quality
63
+
64
+ Beyond required, these lift performance: `google_product_category`, `product_type`, `item_group_id` (links variants), `color`, `size`, `gender`, `age_group`, `sale_price`, `shipping`, `gtin`. Use `item_group_id` so variants cluster correctly — without it, variants compete as separate products.
65
+
66
+ ---
67
+
68
+ ## Output Artifacts
69
+
70
+ | Request | Output |
71
+ |---------|--------|
72
+ | Validate | Per-row + summary PASS / FAIL report |
73
+ | Generate | Channel-ready feed file |
74
+ | Map | Catalog → feed attribute mapping table |
75
+
76
+ A feed is **READY** when every item has all required attributes, price/availability match the PDP, variants share an `item_group_id`, and GTINs are present where they exist.
77
+
78
+ ---
79
+
80
+ ## Related Skills
81
+
82
+ - **commerce-data-model**: the catalog entities mapped into feed attributes.
83
+ - **product-listing**: titles/descriptions reused between PDP and feed.
84
+ - **shipping-tax**: shipping attribute values in the feed.
85
+ - **schema-markup**: Product structured data complements the feed for organic.
@@ -0,0 +1,47 @@
1
+ # Product Feed — Attribute Reference & Catalog Mapping
2
+
3
+ Maps the commerce data model to Google Merchant / Meta Catalog feed attributes. The `feed_validate.py` script enforces the required core.
4
+
5
+ ## Required attributes (every item)
6
+ | Feed attribute | Source (data model) | Rule |
7
+ |----------------|---------------------|------|
8
+ | id | variant.sku | Stable, unique per variant |
9
+ | title | product.title (+ variant) | Front-load product; ≤150 chars; match PDP |
10
+ | description | product.description | Plain, accurate; no promo/ALL CAPS |
11
+ | link | product URL | Canonical, absolute https |
12
+ | image_link | main image | Absolute https; meets resolution min |
13
+ | availability | variant stock | in_stock / out_of_stock / preorder / backorder |
14
+ | price | variant.price | `"21.00 USD"` — matches PDP exactly |
15
+ | brand | product.brand | Required unless exempt category |
16
+ | condition | — | new / refurbished / used |
17
+
18
+ ## Strongly recommended
19
+ | Feed attribute | Source | Why |
20
+ |----------------|--------|-----|
21
+ | gtin | variant.barcode | Improves matching / eligibility |
22
+ | mpn | variant.mpn | Fallback when no GTIN |
23
+ | item_group_id | product.id | Clusters variants (else they compete) |
24
+ | google_product_category | category map | Taxonomy alignment |
25
+ | product_type | primary_category | Your own taxonomy |
26
+ | color / size / gender / age_group | attributes | Apparel facets |
27
+ | sale_price | compare_at logic | Promo pricing |
28
+ | shipping | shipping-tax rules | Overrides account settings |
29
+
30
+ ## Hard rules (disapproval triggers)
31
+ - Feed **price + availability must match the live PDP** exactly.
32
+ - No promotional text in `title`/`description` (no "Free shipping!", no emojis/caps).
33
+ - `image_link` must resolve and meet the channel's minimum resolution.
34
+ - Variants without a shared `item_group_id` are treated as separate products.
35
+
36
+ ## Worked example (CSV row)
37
+ ```csv
38
+ id,title,description,link,image_link,availability,price,brand,condition,gtin,item_group_id
39
+ ACME-TEE-RED-M,"Acme Cotton Tee — Red, Medium","Soft 100% cotton crew-neck tee.",https://shop.example.com/p/acme-tee-red-m,https://shop.example.com/img/acme-tee-red-m.jpg,in_stock,21.00 USD,Acme,new,0123456789012,ACME-TEE
40
+ ```
41
+
42
+ ## Verdict: READY when
43
+ - [ ] All required attributes present and non-empty
44
+ - [ ] price/availability match PDP
45
+ - [ ] valid availability + condition enums
46
+ - [ ] price formatted `amount ISO-currency`
47
+ - [ ] variants share item_group_id; GTIN present where it exists
@@ -0,0 +1,140 @@
1
+ """
2
+ feed_validate.py — Validate a product feed CSV against Google Merchant /
3
+ Meta Catalog requirements (the shared required-attribute core).
4
+
5
+ Checks every row for required attributes, empty values, valid enums
6
+ (availability, condition), and price+currency formatting. Reports a per-row
7
+ and summary verdict. No external dependencies; cross-platform.
8
+
9
+ Usage:
10
+ python feed_validate.py # built-in demo feed
11
+ python feed_validate.py feed.csv # validate your feed
12
+ python feed_validate.py feed.csv --strict # treat recommended as required
13
+
14
+ CSV header (required attributes):
15
+ id,title,description,link,image_link,availability,price,brand,condition
16
+ Recommended columns (warn if absent/empty): gtin, mpn, item_group_id,
17
+ google_product_category, sale_price
18
+ """
19
+
20
+ import argparse
21
+ import csv
22
+ import re
23
+ import sys
24
+
25
+
26
+ REQUIRED = ["id", "title", "description", "link", "image_link",
27
+ "availability", "price", "brand", "condition"]
28
+ RECOMMENDED = ["gtin", "mpn", "item_group_id", "google_product_category"]
29
+
30
+ AVAILABILITY = {"in_stock", "out_of_stock", "preorder", "backorder"}
31
+ CONDITION = {"new", "refurbished", "used"}
32
+ # e.g. "21.00 USD" / "9.99 EUR"
33
+ PRICE_RE = re.compile(r"^\d+(\.\d{1,2})?\s+[A-Z]{3}$")
34
+ URL_RE = re.compile(r"^https?://", re.IGNORECASE)
35
+ TITLE_MAX = 150
36
+ DESC_MAX = 5000
37
+
38
+
39
+ DEMO_FEED = [
40
+ {"id": "ACME-TEE-RED-M", "title": "Acme Cotton Tee — Red, Medium",
41
+ "description": "Soft 100% cotton crew-neck tee.", "link": "https://shop.example.com/p/acme-tee-red-m",
42
+ "image_link": "https://shop.example.com/img/acme-tee-red-m.jpg", "availability": "in_stock",
43
+ "price": "21.00 USD", "brand": "Acme", "condition": "new",
44
+ "gtin": "0123456789012", "item_group_id": "ACME-TEE"},
45
+ # broken row: bad availability, bad price, missing brand, non-url image
46
+ {"id": "ACME-MUG-BLUE", "title": "Acme Mug", "description": "",
47
+ "link": "https://shop.example.com/p/acme-mug", "image_link": "acme-mug.jpg",
48
+ "availability": "available", "price": "9.99", "brand": "", "condition": "brand-new"},
49
+ ]
50
+
51
+
52
+ def validate_row(row, idx, strict):
53
+ errors = []
54
+ warnings = []
55
+
56
+ for attr in REQUIRED:
57
+ if not (row.get(attr) or "").strip():
58
+ errors.append(f"missing required '{attr}'")
59
+
60
+ avail = (row.get("availability") or "").strip().lower()
61
+ if avail and avail not in AVAILABILITY:
62
+ errors.append(f"availability '{avail}' not in {sorted(AVAILABILITY)}")
63
+
64
+ cond = (row.get("condition") or "").strip().lower()
65
+ if cond and cond not in CONDITION:
66
+ errors.append(f"condition '{cond}' not in {sorted(CONDITION)}")
67
+
68
+ price = (row.get("price") or "").strip()
69
+ if price and not PRICE_RE.match(price):
70
+ errors.append(f"price '{price}' must be like '21.00 USD' (amount + ISO currency)")
71
+
72
+ for url_attr in ("link", "image_link"):
73
+ val = (row.get(url_attr) or "").strip()
74
+ if val and not URL_RE.match(val):
75
+ errors.append(f"{url_attr} '{val}' must be an absolute http(s) URL")
76
+
77
+ title = (row.get("title") or "").strip()
78
+ if len(title) > TITLE_MAX:
79
+ warnings.append(f"title > {TITLE_MAX} chars ({len(title)})")
80
+ if len(row.get("description") or "") > DESC_MAX:
81
+ warnings.append(f"description > {DESC_MAX} chars")
82
+
83
+ has_id_link = bool((row.get("item_group_id") or "").strip())
84
+ if not has_id_link:
85
+ warnings.append("no item_group_id (variants won't cluster)")
86
+ if not (row.get("gtin") or "").strip() and not (row.get("mpn") or "").strip():
87
+ warnings.append("no gtin/mpn (weakens product matching)")
88
+
89
+ if strict:
90
+ errors.extend(f"(strict) {w}" for w in warnings)
91
+ warnings = []
92
+ return errors, warnings
93
+
94
+
95
+ def main():
96
+ ap = argparse.ArgumentParser(description="Validate a Google/Meta product feed CSV.")
97
+ ap.add_argument("csv", nargs="?", help="feed CSV. Omit for demo data.")
98
+ ap.add_argument("--strict", action="store_true", help="treat recommended issues as failures")
99
+ args = ap.parse_args()
100
+
101
+ if args.csv:
102
+ try:
103
+ with open(args.csv, newline="", encoding="utf-8") as f:
104
+ rows = list(csv.DictReader(f))
105
+ except OSError as e:
106
+ print(f"[ERROR] cannot read {args.csv}: {e}")
107
+ sys.exit(1)
108
+ else:
109
+ print("[INFO] No CSV given - using built-in demo feed.\n")
110
+ rows = DEMO_FEED
111
+
112
+ if not rows:
113
+ print("[ERROR] feed is empty.")
114
+ sys.exit(1)
115
+
116
+ failed = 0
117
+ for idx, row in enumerate(rows):
118
+ errors, warnings = validate_row(row, idx, args.strict)
119
+ rid = row.get("id") or f"row{idx}"
120
+ if errors:
121
+ failed += 1
122
+ print(f"FAIL {rid}")
123
+ for e in errors:
124
+ print(f" - {e}")
125
+ for w in warnings:
126
+ print(f" ~ {w}")
127
+ else:
128
+ print(f"PASS {rid}")
129
+ for w in warnings:
130
+ print(f" ~ {w}")
131
+
132
+ print()
133
+ passed = len(rows) - failed
134
+ verdict = "READY" if failed == 0 else "NOT-READY"
135
+ print(f"{verdict}: {passed}/{len(rows)} items pass required-attribute checks.")
136
+ sys.exit(0 if failed == 0 else 1)
137
+
138
+
139
+ if __name__ == "__main__":
140
+ main()