claude-code-arcane 1.4.0 → 2.0.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.
- package/CHANGELOG.md +38 -0
- package/README.md +3 -3
- package/dist/cli.js +2 -0
- package/docs/SKILLS-CATALOG.md +6 -2
- package/docs/USER-GUIDE.md +1 -1
- package/docs/coding-standards.md +26 -0
- package/package.json +2 -1
- package/profiles/job-hunt.yaml +12 -2
- package/rules/drafter-reviewer.md +39 -0
- package/skills/cold-outreach/SKILL.md +10 -10
- package/skills/cold-outreach/references/recruiter-playbook.md +5 -5
- package/skills/cover-letter/SKILL.md +8 -8
- package/skills/cv-ats-export/SKILL.md +19 -6
- package/skills/cv-ats-export/scripts/cv_export.py +49 -4
- package/skills/cv-ats-export/scripts/verify_pdf.py +90 -0
- package/skills/cv-tailor/SKILL.md +7 -7
- package/skills/cv-tailor/references/ats-keywords.md +9 -9
- package/skills/interview-prep/SKILL.md +7 -7
- package/skills/interview-prep/references/star-framework.md +10 -10
- package/skills/job-aplicar/SKILL.md +88 -0
- package/skills/job-hunt/SKILL.md +20 -13
- package/skills/job-hunt/references/templates/Aplicacion.md +6 -2
- package/skills/job-hunt/references/templates/CV Custom.md +1 -1
- package/skills/job-hunt/references/templates/Contacto.md +1 -1
- package/skills/job-hunt/references/templates/Dashboard.md +19 -15
- package/skills/job-hunt/references/templates/Perfil.md +2 -2
- package/skills/job-outcome/SKILL.md +55 -0
- package/skills/job-scrape/SKILL.md +95 -0
- package/skills/job-scrape/references/dedup-playbook.md +25 -0
- package/skills/job-scrape/references/getonbrd-cli.md +62 -0
- package/skills/job-scrape/references/getonbrd-urls.md +37 -0
- package/skills/job-scrape/references/linkedin-cli.md +64 -0
- package/skills/job-scrape/references/linkedin-urls.md +42 -0
- package/skills/job-scrape/references/seen_jobs.schema.json +68 -0
- package/skills/job-scrape/scripts/getonbrd_search.py +501 -0
- package/skills/job-scrape/scripts/linkedin_search.py +428 -0
- package/skills/job-search/SKILL.md +22 -19
- package/skills/job-search/references/scoring-rubric.md +8 -8
- package/skills/job-upskill/SKILL.md +58 -0
- package/skills/linkedin-optimize/SKILL.md +5 -5
- package/skills/master-profile/SKILL.md +17 -17
- package/skills/network-map/SKILL.md +7 -7
- package/skills/personal-brand/SKILL.md +10 -10
- package/skills/personal-brand/references/post-pillars.md +14 -14
- package/skills/portfolio-site/SKILL.md +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,41 @@
|
|
|
1
|
+
# [2.0.0](https://github.com/SebastianLuser/claude-code-arcane/compare/v1.4.0...v2.0.0) (2026-07-27)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
* refactor(job-scrape)!: port both search CLIs from TypeScript to Python ([4a30a3e](https://github.com/SebastianLuser/claude-code-arcane/commit/4a30a3e7b30cbf616d01b860620172c602e5c6cf))
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
* **cv-ats-export:** tell a missing verify_pdf.py apart from a missing pypdf ([f2b907e](https://github.com/SebastianLuser/claude-code-arcane/commit/f2b907e4f844725abe2b967941cef78d5fb98a0d))
|
|
10
|
+
* **installer:** skip Python bytecode when copying skill assets ([525967d](https://github.com/SebastianLuser/claude-code-arcane/commit/525967d0270058b9cb5967c932a4969b23e4ea27))
|
|
11
|
+
* **job-scrape:** accept share-button LinkedIn URLs in detail ([7f874e7](https://github.com/SebastianLuser/claude-code-arcane/commit/7f874e71007214540c5814561f8c5e9d46848cea))
|
|
12
|
+
* **job-scrape:** read published dates as UTC in the jobage filter ([fa8e4d7](https://github.com/SebastianLuser/claude-code-arcane/commit/fa8e4d73e68fb1b3f8071cbdd15b1da53882d6e2))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* **cv-ats-export:** add ATS text-layer verification to PDF export ([dd79cc9](https://github.com/SebastianLuser/claude-code-arcane/commit/dd79cc966f88fc3e2ab38a8ebfcc1b51f4f1ad5f))
|
|
18
|
+
* **job-hunt:** adopt extended application-state vocabulary and route to new skills ([4a39add](https://github.com/SebastianLuser/claude-code-arcane/commit/4a39add45301841625581ad4a42bb54442c51a8f))
|
|
19
|
+
* **job-scrape:** confirm the LinkedIn ToS warning before running the CLIs ([294d905](https://github.com/SebastianLuser/claude-code-arcane/commit/294d9054b8c1014bde5babdce928da6d61570102))
|
|
20
|
+
* **profiles:** add job-search tooling suite to job-hunt profile ([b4b061a](https://github.com/SebastianLuser/claude-code-arcane/commit/b4b061a8d724a2f9b4e94c40e83890d564ee9fd8))
|
|
21
|
+
* **rules:** add drafter-reviewer rule for CV and cover review ([8467c38](https://github.com/SebastianLuser/claude-code-arcane/commit/8467c38b2b0e7af98838c3a4d91c3bb0dd36b8c4))
|
|
22
|
+
* **skills:** add job-aplicar, job-outcome and job-upskill skills ([0401ca7](https://github.com/SebastianLuser/claude-code-arcane/commit/0401ca7e0c79b9e619ad064bb726a31d646b3fd3))
|
|
23
|
+
* **skills:** add job-scrape skill with bundled linkedin/getonbrd CLIs ([562bd7b](https://github.com/SebastianLuser/claude-code-arcane/commit/562bd7bd261567efcfaaa17c871f80e47a3f0824))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Performance Improvements
|
|
27
|
+
|
|
28
|
+
* **job-scrape:** add --brief to trim JD text from GetOnBoard search ([f2309e5](https://github.com/SebastianLuser/claude-code-arcane/commit/f2309e59ffd670894829a0730763d71733e2bffd))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### BREAKING CHANGES
|
|
32
|
+
|
|
33
|
+
* the CLI paths changed from
|
|
34
|
+
scripts/<portal>-search/cli.ts to scripts/<portal>_search.py, and the profile's
|
|
35
|
+
Bash permissions moved from node to python. Reinstall the job-hunt profile.
|
|
36
|
+
|
|
37
|
+
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
38
|
+
|
|
1
39
|
# [1.4.0](https://github.com/SebastianLuser/claude-code-arcane/compare/v1.3.0...v1.4.0) (2026-06-22)
|
|
2
40
|
|
|
3
41
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Claude Code Arcane
|
|
2
2
|
|
|
3
|
-
> **
|
|
3
|
+
> **337 skills, 87 agents, 15 hooks and 20 rules for Claude Code — selective deploy by profile.**
|
|
4
4
|
|
|
5
5
|
A configuration harness installable via `npx`. Pick a **profile** that matches your stack and only the relevant tools get installed into your project's `.claude/` directory.
|
|
6
6
|
|
|
@@ -192,7 +192,7 @@ Once installed, manage the installation from within a Claude Code session:
|
|
|
192
192
|
| `+finance` | Investment analysis, financial modeling, SaaS metrics | 3 | business |
|
|
193
193
|
| `+marketing` | Content, growth, SEO/CRO, strategy, analytics | 44 | marketing |
|
|
194
194
|
| `+regulatory` | ISO 13485, GDPR, FDA, SOC 2, ISMS, QMS, MDR | 13 | regulatory |
|
|
195
|
-
| `+job-hunt` | Job search end-to-end — master profile, ATS CV, LinkedIn, portfolio, cover letters, outreach, interview prep |
|
|
195
|
+
| `+job-hunt` | Job search end-to-end — master profile, ATS CV with verification, job scraping with dedup, LinkedIn, portfolio, cover letters, outreach, interview prep | 16 | — |
|
|
196
196
|
| `+ecommerce` | Commerce end-to-end agnóstico de lenguaje — data model, checkout, inventario, órdenes, pagos, promociones, shipping/tax, listings, analytics, feeds, storefront, suscripciones | 12 | ecommerce |
|
|
197
197
|
| `+self-improving` | Agent self-improvement and skill extraction | 2 | — |
|
|
198
198
|
| `+statusline` | Claude Code status bar (branch, division, session info) | 0 | — |
|
|
@@ -352,7 +352,7 @@ claude-code-arcane/
|
|
|
352
352
|
├── profiles/ # 29 profiles (YAML)
|
|
353
353
|
├── agents/ # 13 dirs, 86+ agents (Markdown)
|
|
354
354
|
├── hooks/ # 15 lifecycle hooks (Bash)
|
|
355
|
-
├── rules/ #
|
|
355
|
+
├── rules/ # 20 rules (Markdown)
|
|
356
356
|
├── templates/ # Gamedev templates
|
|
357
357
|
├── docs/ # Documentation
|
|
358
358
|
└── skills-selftest/ # QA framework
|
package/dist/cli.js
CHANGED
|
@@ -117,9 +117,11 @@ function getPackageRoot() {
|
|
|
117
117
|
const thisFile = fileURLToPath(import.meta.url);
|
|
118
118
|
return path2.resolve(path2.dirname(thisFile), "..");
|
|
119
119
|
}
|
|
120
|
+
var COPY_SKIP = /* @__PURE__ */ new Set(["__pycache__", ".pytest_cache"]);
|
|
120
121
|
function copyDirSync(src, dest) {
|
|
121
122
|
fs2.mkdirSync(dest, { recursive: true });
|
|
122
123
|
for (const entry of fs2.readdirSync(src, { withFileTypes: true })) {
|
|
124
|
+
if (COPY_SKIP.has(entry.name) || entry.name.endsWith(".pyc")) continue;
|
|
123
125
|
const srcPath = path2.join(src, entry.name);
|
|
124
126
|
const destPath = path2.join(dest, entry.name);
|
|
125
127
|
if (entry.isDirectory()) {
|
package/docs/SKILLS-CATALOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Skills Catalog — Claude Code Arcane
|
|
2
2
|
|
|
3
|
-
Catalogo completo de los
|
|
3
|
+
Catalogo completo de los 337 skills disponibles para proyectos consumidores. Organizados por division.
|
|
4
4
|
|
|
5
5
|
## Como ejecutar un skill
|
|
6
6
|
|
|
@@ -432,7 +432,7 @@ Desde cualquier proyecto que tenga Arcane configurado, escribi `/` seguido del n
|
|
|
432
432
|
|
|
433
433
|
---
|
|
434
434
|
|
|
435
|
-
## Job Hunt (
|
|
435
|
+
## Job Hunt (16 skills)
|
|
436
436
|
|
|
437
437
|
| Skill | Descripcion | Uso |
|
|
438
438
|
|-------|-------------|-----|
|
|
@@ -443,6 +443,10 @@ Desde cualquier proyecto que tenga Arcane configurado, escribi `/` seguido del n
|
|
|
443
443
|
| `/linkedin-optimize` | Optimiza LinkedIn: headline, About, experiencia con KPIs, keywords, value prop, pitch 30s | `[section\|full]` |
|
|
444
444
|
| `/portfolio-site` | Genera/actualiza portfolio web desde el source-of-truth | `[sync\|scaffold] [repo\|--new]` |
|
|
445
445
|
| `/job-search` | Busca, scorea y prioriza ofertas + plan de busqueda de 7 dias | `[search <query>\|score <url>\|plan]` |
|
|
446
|
+
| `/job-scrape` | Busca ofertas (CLIs LinkedIn + GetOnBoard bundleados) con dedup entre corridas, scorea y ofrece crear notas | `[perfil] [--jobage N]` |
|
|
447
|
+
| `/job-aplicar` | Pipeline completo de una postulacion: fit, CV custom, cover, review, PDF verificado y dashboard | `<url\|nota>` |
|
|
448
|
+
| `/job-outcome` | Registra resultado/avance de una aplicacion y actualiza nota + dashboard | `[empresa]` |
|
|
449
|
+
| `/job-upskill` | Gaps de skills agregados de las aplicaciones + plan de estudio con recursos reales | `[url\|nota]` |
|
|
446
450
|
| `/cover-letter` | Cover letters y mensajes de aplicacion concisos y custom | `[application\|company + role]` |
|
|
447
451
|
| `/cold-outreach` | Mensajes en frio a recruiters/hiring managers + follow-ups post-aplicacion | `[contact\|recruiter + company]` |
|
|
448
452
|
| `/interview-prep` | Prep de entrevista: research, banco de preguntas, respuestas STAR, red flags | `[application\|company + role + round]` |
|
package/docs/USER-GUIDE.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## What is Arcane?
|
|
4
4
|
|
|
5
|
-
Arcane is a configuration harness for [Claude Code](https://docs.anthropic.com/en/docs/claude-code). It provides a curated library of **
|
|
5
|
+
Arcane is a configuration harness for [Claude Code](https://docs.anthropic.com/en/docs/claude-code). It provides a curated library of **337 skills**, **87 agents**, **15 hooks**, and **20 rules** that you selectively deploy into any project. Instead of shipping everything to every project (wasting tokens and degrading performance), you pick a **profile** that matches your stack and only the relevant tools get installed.
|
|
6
6
|
|
|
7
7
|
## Table of Contents
|
|
8
8
|
|
package/docs/coding-standards.md
CHANGED
|
@@ -18,6 +18,32 @@ Las rules path-scoped específicas viven en `.claude/rules/`.
|
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
+
## Elección de lenguaje en este repo
|
|
22
|
+
|
|
23
|
+
El lenguaje lo dicta **el contexto de ejecución**, no la preferencia. Hay cuatro contextos y uno solo por cada uno:
|
|
24
|
+
|
|
25
|
+
| Contexto | Lenguaje | Por qué | Garantía en CI |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| Installer (`src/`) | **TypeScript** | Es el paquete npm publicado: el único código con build (`tsup`) y typechecker | `npm run build`, `tsc --noEmit`, `vitest` |
|
|
28
|
+
| Hooks de lifecycle (`hooks/`, `skills/*/hooks/`) | **Bash** | Claude Code los invoca por path, sin intérprete de por medio | `bash -n` sobre todos |
|
|
29
|
+
| Scripts de skill (`skills/*/scripts/`) | **Python 3, solo stdlib** | Se copian al proyecto del usuario y corren ahí: sin build, sin `package.json`, sin `node_modules` | Specs en `tests/` (ver Testing) |
|
|
30
|
+
| Templates (`*/templates/`) | **El del proyecto destino** | Son contenido que se emite al proyecto del usuario; el repo nunca los ejecuta | N/A |
|
|
31
|
+
|
|
32
|
+
**TypeScript fuera de `src/` no es una elección de lenguaje: es un requisito de runtime disfrazado.** Sin build step, un `.ts` solo corre con el type stripping nativo de Node 24+, que la matriz de CI (20 y 22) no cubre. Si el script tiene que correr en la máquina del usuario, es Python.
|
|
33
|
+
|
|
34
|
+
**Dependencias opcionales:** permitidas solo con degradación explícita. Referencia: `cv-ats-export` usa `pypdf` si está y reporta `[ATS SKIP]` si no, sin romper el export.
|
|
35
|
+
|
|
36
|
+
### Escotilla de escape
|
|
37
|
+
|
|
38
|
+
Otro lenguaje **únicamente cuando una dependencia obligatoria lo impone** — nunca por gusto ni por familiaridad. Requiere una línea de justificación en el SKILL.md del skill. Los dos casos vigentes:
|
|
39
|
+
|
|
40
|
+
- `pdf-generator/scripts/render_cover.js` → Node, porque **Playwright es una librería de Node**.
|
|
41
|
+
- `docx-generator/scripts/` (`.cs`, `.slnx`, `setup.ps1`) → .NET, porque **vendorea un proyecto .NET** (MiniMaxAIDocx); el `.ps1` es su setup en Windows.
|
|
42
|
+
|
|
43
|
+
Si podés hacerlo con la stdlib de Python, la escotilla no aplica.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
21
47
|
## Naming
|
|
22
48
|
|
|
23
49
|
- **Variables/funciones:** camelCase (JS/TS/Java/C#) o snake_case (Python/Rust) o PascalCase (Go exports)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-arcane",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Skills, agents, hooks and rules for Claude Code — installable via npx arcane",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"dev": "tsup src/cli.ts --format esm --target node20 --watch",
|
|
23
23
|
"test": "vitest run",
|
|
24
24
|
"test:watch": "vitest",
|
|
25
|
+
"test:skills": "python -m unittest discover -s tests -p \"test_*.py\"",
|
|
25
26
|
"prepublishOnly": "npm run build",
|
|
26
27
|
"release": "semantic-release"
|
|
27
28
|
},
|
package/profiles/job-hunt.yaml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
name: job-hunt
|
|
2
|
-
description: "Job Hunt — busqueda laboral end-to-end: perfil maestro, CV ATS, LinkedIn, portfolio, cover letters, outreach a recruiters, scoring de ofertas y prep de entrevistas"
|
|
2
|
+
description: "Job Hunt — busqueda laboral end-to-end: perfil maestro, CV ATS con verificacion, scraping de ofertas con dedup, pipeline de postulacion, LinkedIn, portfolio, cover letters, outreach a recruiters, scoring de ofertas, gaps/upskill y prep de entrevistas"
|
|
3
3
|
type: addon
|
|
4
4
|
|
|
5
5
|
skills:
|
|
@@ -10,6 +10,10 @@ skills:
|
|
|
10
10
|
- linkedin-optimize
|
|
11
11
|
- portfolio-site
|
|
12
12
|
- job-search
|
|
13
|
+
- job-scrape
|
|
14
|
+
- job-aplicar
|
|
15
|
+
- job-outcome
|
|
16
|
+
- job-upskill
|
|
13
17
|
- cover-letter
|
|
14
18
|
- cold-outreach
|
|
15
19
|
- interview-prep
|
|
@@ -18,7 +22,7 @@ skills:
|
|
|
18
22
|
|
|
19
23
|
rules:
|
|
20
24
|
universal:
|
|
21
|
-
|
|
25
|
+
- drafter-reviewer
|
|
22
26
|
gamedev:
|
|
23
27
|
[]
|
|
24
28
|
|
|
@@ -29,7 +33,13 @@ permissions:
|
|
|
29
33
|
allow:
|
|
30
34
|
- "Bash(python *cv_export.py*)"
|
|
31
35
|
- "Bash(python3 *cv_export.py*)"
|
|
36
|
+
- "Bash(python *verify_pdf.py*)"
|
|
37
|
+
- "Bash(python3 *verify_pdf.py*)"
|
|
32
38
|
- "Bash(python *network_map.py*)"
|
|
33
39
|
- "Bash(python3 *network_map.py*)"
|
|
40
|
+
- "Bash(python *linkedin_search.py*)"
|
|
41
|
+
- "Bash(python3 *linkedin_search.py*)"
|
|
42
|
+
- "Bash(python *getonbrd_search.py*)"
|
|
43
|
+
- "Bash(python3 *getonbrd_search.py*)"
|
|
34
44
|
deny:
|
|
35
45
|
[]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Drafter-Reviewer Rule (CVs y covers)
|
|
2
|
+
|
|
3
|
+
Adaptado del workflow `/apply` de MadsLorentzen/ai-job-search. Todo CV custom o cover letter para una aplicación pasa por un reviewer de contexto fresco ANTES de exportarse a PDF. El que redacta no se auto-revisa.
|
|
4
|
+
|
|
5
|
+
Las rutas son relativas al career workspace (`./career-workspace/` o env `CAREER_WORKSPACE`).
|
|
6
|
+
|
|
7
|
+
## Cuándo aplica
|
|
8
|
+
|
|
9
|
+
- Al terminar el borrador de un CV custom (flujo cv-tailor) o de una cover / mensaje de aplicación (flujo cover-letter) destinado a una postulación concreta.
|
|
10
|
+
- NO aplica a ediciones menores de un CV ya revisado (typos, cambiar una fecha) ni a los CVs base de `02-CVs/` fuera de una postulación.
|
|
11
|
+
|
|
12
|
+
## El paso reviewer
|
|
13
|
+
|
|
14
|
+
Lanzar UN agente `general-purpose` de contexto fresco vía el Agent tool, con este contenido inline en el prompt (para que no dependa de leer archivos de la conversación):
|
|
15
|
+
|
|
16
|
+
1. El texto completo de la job description.
|
|
17
|
+
2. El borrador del CV y/o cover, verbatim.
|
|
18
|
+
3. Instrucción de lectura acotada: solo puede leer `01-Perfiles/<perfil usado>.md` del workspace. NO debe leer los templates ni el resto del workspace - critica contenido, no estructura.
|
|
19
|
+
4. Instrucción de research: búsqueda web breve sobre la empresa (misión, producto, noticias recientes, cultura) para detectar ángulos no aprovechados.
|
|
20
|
+
|
|
21
|
+
El reviewer devuelve dos partes:
|
|
22
|
+
|
|
23
|
+
- **Parte A - reemplazos mecánicos:** lista JSON de objetos `{ "old_string": "<texto exacto del borrador>", "new_string": "<reemplazo>", "motivo": "<una línea>" }`. El `old_string` debe ser cita textual para aplicarse con Edit sin ambigüedad.
|
|
24
|
+
- **Parte B - sugerencias narrativas**, agrupadas por categoría:
|
|
25
|
+
- Keywords ATS de la JD que faltan o aparecen solo como sinónimo
|
|
26
|
+
- Ángulos de empresa no aprovechados (del research)
|
|
27
|
+
- Bullets que se pueden reformular como logro medible
|
|
28
|
+
- Tono / estilo (registro, longitud, muletillas)
|
|
29
|
+
|
|
30
|
+
## Reglas de aplicación del feedback
|
|
31
|
+
|
|
32
|
+
- **Una sola ronda.** El drafter aplica la Parte A, incorpora de la Parte B lo que corresponda, y sigue. Sin ida y vuelta iterativo.
|
|
33
|
+
- **Never stuff keywords:** si una keyword de la JD es un gap real del candidato, NO se agrega al CV; se reconoce honestamente en el cover si vale la pena.
|
|
34
|
+
- Nada de guiones largos en el resultado final: si el reviewer sugiere texto con em-dash o en-dash, se normaliza a `-` al aplicarlo.
|
|
35
|
+
- Recién después de aplicar el feedback se exporta: `python .claude/skills/cv-ats-export/scripts/cv_export.py "<CV>"` (o la copia instalada en `<workspace>/tools/`; incluye verificación ATS automática de la capa de texto).
|
|
36
|
+
|
|
37
|
+
## Registro
|
|
38
|
+
|
|
39
|
+
En la nota de aplicación (`03-Aplicaciones/`), dejar en `## Notas` un resumen de 3-5 decisiones de tailoring (qué se enfatizó, qué ángulo de empresa se usó, qué gap se reconoció). Sirve para calibrar futuras aplicaciones y para el prep de entrevista.
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cold-outreach
|
|
3
|
-
description: "Write cold LinkedIn/email messages from a job-seeker to recruiters, hiring managers and referrals
|
|
3
|
+
description: "Write cold LinkedIn/email messages from a job-seeker to recruiters, hiring managers and referrals - plus post-application follow-up sequences that get replies. For B2B sales outreach use cold-email instead. Triggers: mensaje en frio recruiter, escribirle a un reclutador, follow up postulacion, networking message, pedir referido, contactar hiring manager."
|
|
4
4
|
argument-hint: "[contact-note | recruiter + company]"
|
|
5
5
|
category: "career"
|
|
6
6
|
user-invocable: true
|
|
7
7
|
allowed-tools: Read, Glob, Grep, Write, Edit, WebFetch
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
# Cold Outreach
|
|
10
|
+
# Cold Outreach - Job-seeker → Recruiter / Hiring Manager
|
|
11
11
|
|
|
12
|
-
Escribís mensajes en frío de un **candidato** a recruiters, hiring managers y referidos, y secuencias de **follow-up** post-aplicación que reciben respuesta. Esto NO es venta B2B (para eso está `/cold-email`)
|
|
12
|
+
Escribís mensajes en frío de un **candidato** a recruiters, hiring managers y referidos, y secuencias de **follow-up** post-aplicación que reciben respuesta. Esto NO es venta B2B (para eso está `/cold-email`) - el ángulo es conseguir una conversación o un referido, sin sonar a spam ni a desesperación.
|
|
13
13
|
|
|
14
14
|
## Cuándo usar cada variante
|
|
15
15
|
|
|
@@ -24,7 +24,7 @@ Escribís mensajes en frío de un **candidato** a recruiters, hiring managers y
|
|
|
24
24
|
## Principios
|
|
25
25
|
|
|
26
26
|
- **Personalizá la primera línea.** Algo real de esa persona/empresa/rol. Si sirve para 100 personas, no sirve para ninguna.
|
|
27
|
-
- **Corto.** LinkedIn: 50
|
|
27
|
+
- **Corto.** LinkedIn: 50-125 palabras. La connection note: <300 caracteres.
|
|
28
28
|
- **Una pregunta / un CTA.** Bajá la fricción de responder.
|
|
29
29
|
- **Vos resolvés algo para ellos**, no "estoy buscando trabajo, ¿me ayudás?". El foco es el valor que aportás al equipo.
|
|
30
30
|
- **Sin paredes de texto, sin CV adjunto en el primer toque** (salvo que lo pidan).
|
|
@@ -33,26 +33,26 @@ Escribís mensajes en frío de un **candidato** a recruiters, hiring managers y
|
|
|
33
33
|
## Estructura de un primer mensaje
|
|
34
34
|
|
|
35
35
|
1. **Gancho personal** (1 línea): por qué *a esta persona*.
|
|
36
|
-
2. **Quién sos + fit** (1
|
|
36
|
+
2. **Quién sos + fit** (1-2 líneas): rol + el logro más relevante para ellos.
|
|
37
37
|
3. **CTA suave** (1 línea): ¿15 min para charlar? / ¿abierto a una intro? / dejé mi aplicación, encantado de dar contexto.
|
|
38
38
|
|
|
39
39
|
## Secuencia de follow-up post-aplicación
|
|
40
40
|
|
|
41
|
-
- **Día 0**
|
|
42
|
-
- **Día 4
|
|
43
|
-
- **Día 10
|
|
41
|
+
- **Día 0** - aplicación enviada (+ mensaje al recruiter/hiring manager si tenés el contacto).
|
|
42
|
+
- **Día 4-5** - follow-up 1: reafirmá interés + agregá *algo nuevo* (un proyecto relevante, una idea sobre su producto). No "¿novedades?".
|
|
43
|
+
- **Día 10-12** - follow-up 2 (último): breve, profesional, dejá la puerta abierta. Si no hay respuesta, cerrás el loop con dignidad.
|
|
44
44
|
|
|
45
45
|
Cada follow-up debe tener un **gancho propio** y leerse solo, sin depender de los anteriores.
|
|
46
46
|
|
|
47
47
|
## Proceso
|
|
48
48
|
|
|
49
49
|
1. Leer la nota de `05-Contactos/` (o crearla) y la de `04-Empresas/`.
|
|
50
|
-
2. Investigar a la persona (rol, equipo, algo reciente)
|
|
50
|
+
2. Investigar a la persona (rol, equipo, algo reciente) - WebFetch del perfil público si hay URL.
|
|
51
51
|
3. Elegir variante + canal.
|
|
52
52
|
4. Draftear mensaje + 1 variante de apertura.
|
|
53
53
|
5. Registrar en `05-Contactos/` (historial de interacciones) y planificar el follow-up.
|
|
54
54
|
|
|
55
|
-
> Nota: Claude no accede a tu LinkedIn ni envía mensajes
|
|
55
|
+
> Nota: Claude no accede a tu LinkedIn ni envía mensajes - redacta para que vos copies/pegues y registres la interacción.
|
|
56
56
|
|
|
57
57
|
## Idioma
|
|
58
58
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Recruiter / Hiring Manager Playbook
|
|
2
2
|
|
|
3
|
-
Plantillas y psicología para outreach de candidato. Adaptá siempre la primera línea
|
|
3
|
+
Plantillas y psicología para outreach de candidato. Adaptá siempre la primera línea - las plantillas son esqueleto, no copy-paste.
|
|
4
4
|
|
|
5
5
|
## Por qué responden (y por qué no)
|
|
6
6
|
|
|
7
|
-
Responden cuando: el mensaje es corto, claro sobre el fit, fácil de responder, y se nota que es para *ellos*. No responden cuando: es genérico, largo, pide demasiado de entrada, o suena desesperado. El recruiter recibe decenas por día
|
|
7
|
+
Responden cuando: el mensaje es corto, claro sobre el fit, fácil de responder, y se nota que es para *ellos*. No responden cuando: es genérico, largo, pide demasiado de entrada, o suena desesperado. El recruiter recibe decenas por día - el filtro es "¿esto me ahorra trabajo o me lo agrega?".
|
|
8
8
|
|
|
9
9
|
## Plantillas
|
|
10
10
|
|
|
@@ -37,14 +37,14 @@ Hola {nombre}, me interesa mucho {empresa/área}. Vengo de {1 cosa}.
|
|
|
37
37
|
Me encantaría conectar y, si surge, charlar sobre {rol/equipo}.
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
### 5. Follow-up 1 (día 4
|
|
40
|
+
### 5. Follow-up 1 (día 4-5) - con valor nuevo
|
|
41
41
|
```
|
|
42
42
|
Hola {nombre}, te escribo para reafirmar mi interés en {rol}.
|
|
43
43
|
Sumo un dato: {proyecto/idea relevante para su producto}.
|
|
44
44
|
Quedo a disposición para lo que necesiten del proceso.
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
### 6. Follow-up 2 (día 10
|
|
47
|
+
### 6. Follow-up 2 (día 10-12) - cierre digno
|
|
48
48
|
```
|
|
49
49
|
Hola {nombre}, entiendo que están con mucho.
|
|
50
50
|
Dejo la puerta abierta por si avanza {rol}; me encantaría sumar.
|
|
@@ -55,7 +55,7 @@ Dejo la puerta abierta por si avanza {rol}; me encantaría sumar.
|
|
|
55
55
|
|
|
56
56
|
- Máximo 2 follow-ups. Después, soltar.
|
|
57
57
|
- Cada follow-up agrega algo (no "¿novedades?").
|
|
58
|
-
- Espaciar 4
|
|
58
|
+
- Espaciar 4-5 días. Nunca el mismo día ni días consecutivos.
|
|
59
59
|
- Registrar cada toque en la nota de `05-Contactos/`.
|
|
60
60
|
|
|
61
61
|
## Tono
|
|
@@ -7,9 +7,9 @@ user-invocable: true
|
|
|
7
7
|
allowed-tools: Read, Glob, Grep, Write, Edit, WebFetch
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
# Cover Letter
|
|
10
|
+
# Cover Letter - Mensaje de aplicación de élite
|
|
11
11
|
|
|
12
|
-
Escribís cover letters y mensajes de aplicación **concisos, seguros y custom**
|
|
12
|
+
Escribís cover letters y mensajes de aplicación **concisos, seguros y custom** - que suenan a una persona que entendió el rol y la empresa, no a una plantilla. El objetivo: que el lector quiera leer el CV.
|
|
13
13
|
|
|
14
14
|
## Inputs
|
|
15
15
|
|
|
@@ -20,19 +20,19 @@ Escribís cover letters y mensajes de aplicación **concisos, seguros y custom**
|
|
|
20
20
|
|
|
21
21
|
## Principios
|
|
22
22
|
|
|
23
|
-
- **Una página máximo; idealmente 150
|
|
23
|
+
- **Una página máximo; idealmente 150-250 palabras** para mensajes, 250-350 para carta formal.
|
|
24
24
|
- **El primer renglón gana o pierde.** Nada de "I am writing to apply for…". Abrí con un gancho específico: un logro relevante, un punto de conexión con la empresa, o por qué este rol te mueve.
|
|
25
|
-
- **Mostrá fit, no historia.** 1
|
|
25
|
+
- **Mostrá fit, no historia.** 1-2 logros que mapean directo a lo que piden, con número.
|
|
26
26
|
- **Específico de la empresa.** Una frase que demuestre que investigaste (producto, valor, problema que resuelven). Si la podés pegar en otra aplicación, no sirve.
|
|
27
27
|
- **Confiado, no arrogante; cálido, no servil.** Ni "would be honored", ni "I'm the best candidate".
|
|
28
28
|
- **CTA simple al final.** Disponibilidad / ganas de charlar, sin rogar.
|
|
29
29
|
|
|
30
30
|
## Estructura (carta formal)
|
|
31
31
|
|
|
32
|
-
1. **Hook**
|
|
33
|
-
2. **Fit**
|
|
34
|
-
3. **Empresa**
|
|
35
|
-
4. **Cierre**
|
|
32
|
+
1. **Hook** - gancho específico (logro o conexión real).
|
|
33
|
+
2. **Fit** - 1-2 logros mapeados a must-haves del JD, con métrica.
|
|
34
|
+
3. **Empresa** - por qué *esta* empresa/rol (research real).
|
|
35
|
+
4. **Cierre** - CTA breve + gracias.
|
|
36
36
|
|
|
37
37
|
## Estructura (mensaje corto / LinkedIn / email)
|
|
38
38
|
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cv-ats-export
|
|
3
|
-
description: "Export a Markdown CV to an ATS-compliant PDF (single column, selectable text, A4) using headless Chrome/Edge
|
|
3
|
+
description: "Export a Markdown CV to an ATS-compliant PDF (single column, selectable text, A4) using headless Chrome/Edge - no Obsidian or design tool needed. Triggers: exportar CV a PDF, generar PDF del CV, CV ATS PDF, convertir CV markdown a PDF, imprimir CV."
|
|
4
4
|
argument-hint: "[cv-name | all] [--workspace <path>]"
|
|
5
5
|
category: "career"
|
|
6
6
|
user-invocable: true
|
|
7
7
|
allowed-tools: Read, Glob, Grep, Bash, Write
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
# CV ATS Export
|
|
10
|
+
# CV ATS Export - Markdown → PDF ATS-compliant
|
|
11
11
|
|
|
12
|
-
Convertís un CV en Markdown a un **PDF que pasa filtros ATS**: una sola columna, texto seleccionable (no imagen), A4, tipografía limpia. Usa Chrome o Edge en modo headless
|
|
12
|
+
Convertís un CV en Markdown a un **PDF que pasa filtros ATS**: una sola columna, texto seleccionable (no imagen), A4, tipografía limpia. Usa Chrome o Edge en modo headless - no requiere Obsidian, LaTeX ni herramienta de diseño.
|
|
13
13
|
|
|
14
|
-
El motor es `scripts/cv_export.py
|
|
14
|
+
El motor es `scripts/cv_export.py` + `scripts/verify_pdf.py` (verificación ATS post-export). La primera vez, instalá ambos en el workspace (`tools/`) para que queden versionados con los CVs; o corrélos directo desde el skill (van juntos: `cv_export` importa `verify_pdf` desde su mismo directorio).
|
|
15
15
|
|
|
16
16
|
## Requisitos
|
|
17
17
|
|
|
18
18
|
- **Python 3** en el PATH.
|
|
19
19
|
- **Google Chrome o Microsoft Edge** instalado (el script autodetecta rutas estándar en Windows/macOS/Linux).
|
|
20
|
+
- **`pypdf` (opcional)** para la verificación ATS automática: `pip install pypdf`. Sin pypdf el export funciona igual y reporta `[ATS SKIP]`.
|
|
20
21
|
- CVs en Markdown dentro de `02-CVs/` del career workspace, con headers (`# Nombre`, `## Sección`), bullets y `---` como separadores.
|
|
21
22
|
|
|
22
23
|
## Uso
|
|
@@ -30,6 +31,9 @@ python scripts/cv_export.py "CV - Acme - Backend"
|
|
|
30
31
|
|
|
31
32
|
# Workspace explícito
|
|
32
33
|
python scripts/cv_export.py --workspace ./career-workspace "CV - Acme - Backend"
|
|
34
|
+
|
|
35
|
+
# Saltar la verificación ATS
|
|
36
|
+
python scripts/cv_export.py --no-verify "CV - Acme - Backend"
|
|
33
37
|
```
|
|
34
38
|
|
|
35
39
|
El script:
|
|
@@ -37,6 +41,15 @@ El script:
|
|
|
37
41
|
2. Lee el `.md`, separa frontmatter, convierte el cuerpo a HTML con el CSS ATS embebido.
|
|
38
42
|
3. Imprime a PDF con Chrome/Edge headless (`--headless=new --print-to-pdf`).
|
|
39
43
|
4. Guarda en `02-CVs/exports/`. El nombre sale del frontmatter `archivo_pdf` si existe; si no, del nombre del `.md` (sin el prefijo `CV - `).
|
|
44
|
+
5. **Verifica la capa de texto ATS** con `verify_pdf.py` (pypdf): texto extraíble (mínimo 200 chars), que el nombre del H1 y el email sobrevivan al export, y avisa si supera las 2 páginas. Reporta `[ATS OK]` / `[ATS WARN]` / `[ATS SKIP]`; nunca rompe el export. Se salta con `--no-verify`.
|
|
45
|
+
|
|
46
|
+
Los dos `[ATS SKIP]` son distintos: `verify_pdf.py not found next to cv_export.py` significa que copiaste solo un archivo al workspace (instalar pypdf no cambia nada); `pypdf not installed` es el que se resuelve con `pip install pypdf`.
|
|
47
|
+
|
|
48
|
+
`verify_pdf.py` también funciona standalone para chequear cualquier PDF:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
python scripts/verify_pdf.py "02-CVs/exports/Backend.pdf" --min-chars 200 --max-pages 2 --contains "Jane Doe"
|
|
52
|
+
```
|
|
40
53
|
|
|
41
54
|
## Markdown soportado
|
|
42
55
|
|
|
@@ -51,12 +64,12 @@ El script:
|
|
|
51
64
|
|
|
52
65
|
## Personalizar el estilo
|
|
53
66
|
|
|
54
|
-
El CSS ATS está en la constante `CSS` dentro de `scripts/cv_export.py` (tamaño de fuente, márgenes A4, estilos de h1/h2). Editá ahí si querés ajustar tipografía o espaciado
|
|
67
|
+
El CSS ATS está en la constante `CSS` dentro de `scripts/cv_export.py` (tamaño de fuente, márgenes A4, estilos de h1/h2). Editá ahí si querés ajustar tipografía o espaciado - mantené una sola columna y texto real.
|
|
55
68
|
|
|
56
69
|
## Reglas
|
|
57
70
|
|
|
58
71
|
- No metas tablas, columnas ni imágenes en el CV: rompen el parseo ATS.
|
|
59
|
-
-
|
|
72
|
+
- Atendé los `[ATS WARN]`: un PDF-imagen o sin el nombre/email extraíbles no pasa filtros ATS. Usá `--no-verify` solo para iterar rápido sobre el layout.
|
|
60
73
|
- No commitees PDFs con datos sensibles a un remoto sin confirmación.
|
|
61
74
|
|
|
62
75
|
## Handoff
|
|
@@ -8,6 +8,12 @@ Usage (from anywhere; the script locates the career workspace):
|
|
|
8
8
|
python cv_export.py # all base CVs (CV - *.md)
|
|
9
9
|
python cv_export.py "CV - Acme - Backend" # a single CV (with/without .md)
|
|
10
10
|
python cv_export.py --workspace ./career-workspace "CV - Acme"
|
|
11
|
+
python cv_export.py --no-verify ... # skip the ATS verification
|
|
12
|
+
|
|
13
|
+
After exporting, the PDF text layer is verified with verify_pdf.py (pypdf):
|
|
14
|
+
extractable text, the H1 name and the email must survive the export, and a
|
|
15
|
+
warning is printed above 2 pages. Reports [ATS OK] / [ATS WARN]; if pypdf is
|
|
16
|
+
not installed, [ATS SKIP] without breaking the export.
|
|
11
17
|
|
|
12
18
|
Workspace resolution order:
|
|
13
19
|
1. --workspace <path> flag
|
|
@@ -204,7 +210,41 @@ def find_browser():
|
|
|
204
210
|
return None
|
|
205
211
|
|
|
206
212
|
|
|
207
|
-
def
|
|
213
|
+
def verify_ats(pdf_path, body):
|
|
214
|
+
"""Verify the exported PDF's text layer. Never breaks the export: reports."""
|
|
215
|
+
# Two distinct failures, two distinct messages: verify_pdf.py missing next to
|
|
216
|
+
# this script (installing pypdf would not help) vs pypdf missing, which
|
|
217
|
+
# verify_pdf only imports when it actually reads the PDF.
|
|
218
|
+
try:
|
|
219
|
+
from verify_pdf import verify
|
|
220
|
+
except ImportError:
|
|
221
|
+
print(f" [ATS SKIP] verify_pdf.py not found next to {Path(__file__).name}")
|
|
222
|
+
return
|
|
223
|
+
|
|
224
|
+
contains = []
|
|
225
|
+
m = re.search(r"^#\s+(.+)$", body, re.MULTILINE)
|
|
226
|
+
if m:
|
|
227
|
+
contains.append(re.sub(r"\*|\[|\]\([^)]*\)", "", m.group(1)).strip())
|
|
228
|
+
m = re.search(r"[\w.+-]+@[\w-]+\.[\w.]+", body)
|
|
229
|
+
if m:
|
|
230
|
+
contains.append(m.group(0))
|
|
231
|
+
|
|
232
|
+
try:
|
|
233
|
+
problems = verify(pdf_path, min_chars=200, contains=contains, max_pages=2)
|
|
234
|
+
except ImportError:
|
|
235
|
+
print(" [ATS SKIP] pypdf not installed (pip install pypdf)")
|
|
236
|
+
return
|
|
237
|
+
except Exception as e:
|
|
238
|
+
problems = [f"could not verify: {e}"]
|
|
239
|
+
|
|
240
|
+
if problems:
|
|
241
|
+
for p in problems:
|
|
242
|
+
print(f" [ATS WARN] {p}")
|
|
243
|
+
else:
|
|
244
|
+
print(" [ATS OK] text layer verified (name + email extractable)")
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def export(md_path, browser, cv_dir, export_dir, check_ats=True):
|
|
208
248
|
text = md_path.read_text(encoding="utf-8")
|
|
209
249
|
fm, body = strip_frontmatter(text)
|
|
210
250
|
|
|
@@ -252,12 +292,15 @@ def export(md_path, browser, cv_dir, export_dir):
|
|
|
252
292
|
|
|
253
293
|
size_kb = pdf_path.stat().st_size // 1024
|
|
254
294
|
print(f"[OK] {md_path.name} -> {pdf_path} ({size_kb} KB)")
|
|
295
|
+
if check_ats:
|
|
296
|
+
verify_ats(pdf_path, body)
|
|
255
297
|
return True
|
|
256
298
|
|
|
257
299
|
|
|
258
300
|
def parse_args(argv):
|
|
259
301
|
workspace = None
|
|
260
302
|
names = []
|
|
303
|
+
check_ats = True
|
|
261
304
|
i = 0
|
|
262
305
|
while i < len(argv):
|
|
263
306
|
a = argv[i]
|
|
@@ -266,14 +309,16 @@ def parse_args(argv):
|
|
|
266
309
|
workspace = argv[i] if i < len(argv) else None
|
|
267
310
|
elif a.startswith("--workspace="):
|
|
268
311
|
workspace = a.split("=", 1)[1]
|
|
312
|
+
elif a == "--no-verify":
|
|
313
|
+
check_ats = False
|
|
269
314
|
else:
|
|
270
315
|
names.append(a)
|
|
271
316
|
i += 1
|
|
272
|
-
return workspace, names
|
|
317
|
+
return workspace, names, check_ats
|
|
273
318
|
|
|
274
319
|
|
|
275
320
|
def main():
|
|
276
|
-
workspace, names = parse_args(sys.argv[1:])
|
|
321
|
+
workspace, names, check_ats = parse_args(sys.argv[1:])
|
|
277
322
|
|
|
278
323
|
browser = find_browser()
|
|
279
324
|
if not browser:
|
|
@@ -298,7 +343,7 @@ def main():
|
|
|
298
343
|
print(f"[ERROR] No CVs (CV - *.md) found in {cv_dir}.")
|
|
299
344
|
sys.exit(1)
|
|
300
345
|
|
|
301
|
-
ok = all([export(t, browser, cv_dir, export_dir) for t in targets])
|
|
346
|
+
ok = all([export(t, browser, cv_dir, export_dir, check_ats) for t in targets])
|
|
302
347
|
sys.exit(0 if ok else 1)
|
|
303
348
|
|
|
304
349
|
|