claude-code-arcane 1.1.1 → 1.3.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 (61) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +2 -0
  3. package/agents/engineering/dotnet-engineer.md +78 -0
  4. package/dist/cli.js +284 -72
  5. package/docs/RELEASE-SETUP.md +99 -0
  6. package/docs/SKILLS-CATALOG.md +26 -3
  7. package/docs/presentations/arcane-overview-12.pptx +0 -0
  8. package/docs/presentations/arcane-overview.pptx +0 -0
  9. package/docs/presentations/build_arcane_deck.py +310 -0
  10. package/docs/presentations/build_arcane_deck_12.py +399 -0
  11. package/package.json +1 -1
  12. package/profiles/backend-dotnet.yaml +54 -0
  13. package/profiles/job-hunt.yaml +35 -0
  14. package/profiles/unity-design.yaml +1 -0
  15. package/profiles/unity-dev.yaml +1 -0
  16. package/rules/dotnet-code.md +64 -0
  17. package/skills/cold-outreach/SKILL.md +65 -0
  18. package/skills/cold-outreach/references/recruiter-playbook.md +65 -0
  19. package/skills/cover-letter/SKILL.md +66 -0
  20. package/skills/cv-ats-export/SKILL.md +64 -0
  21. package/skills/cv-ats-export/scripts/cv_export.py +306 -0
  22. package/skills/cv-tailor/SKILL.md +70 -0
  23. package/skills/cv-tailor/references/ats-keywords.md +46 -0
  24. package/skills/dotnet-architecture/SKILL.md +66 -0
  25. package/skills/dotnet-architecture/references/anti-patterns.md +12 -0
  26. package/skills/dotnet-architecture/references/checklist.md +19 -0
  27. package/skills/dotnet-architecture/references/patterns.md +118 -0
  28. package/skills/dotnet-architecture/references/project-structure.md +78 -0
  29. package/skills/dotnet-best-practices/SKILL.md +76 -0
  30. package/skills/dotnet-best-practices/references/api-design.md +75 -0
  31. package/skills/dotnet-best-practices/references/architecture.md +62 -0
  32. package/skills/dotnet-best-practices/references/async.md +62 -0
  33. package/skills/dotnet-best-practices/references/database.md +69 -0
  34. package/skills/dotnet-best-practices/references/dependency-injection.md +73 -0
  35. package/skills/dotnet-best-practices/references/devops.md +76 -0
  36. package/skills/dotnet-best-practices/references/error-handling.md +72 -0
  37. package/skills/dotnet-best-practices/references/performance.md +63 -0
  38. package/skills/dotnet-best-practices/references/security.md +73 -0
  39. package/skills/dotnet-best-practices/references/testing.md +76 -0
  40. package/skills/dotnet-scaffold/SKILL.md +99 -0
  41. package/skills/install-mcp/SKILL.md +107 -0
  42. package/skills/install-mcp/references/manual-setup.md +92 -0
  43. package/skills/interview-prep/SKILL.md +69 -0
  44. package/skills/interview-prep/references/star-framework.md +42 -0
  45. package/skills/job-hunt/SKILL.md +92 -0
  46. package/skills/job-hunt/references/templates/Aplicacion.md +48 -0
  47. package/skills/job-hunt/references/templates/CV Custom.md +53 -0
  48. package/skills/job-hunt/references/templates/Contacto.md +30 -0
  49. package/skills/job-hunt/references/templates/Dashboard.md +45 -0
  50. package/skills/job-hunt/references/templates/Empresa.md +36 -0
  51. package/skills/job-hunt/references/templates/Entrevista.md +44 -0
  52. package/skills/job-hunt/references/templates/Perfil.md +38 -0
  53. package/skills/job-search/SKILL.md +83 -0
  54. package/skills/job-search/references/scoring-rubric.md +43 -0
  55. package/skills/linkedin-optimize/SKILL.md +79 -0
  56. package/skills/master-profile/SKILL.md +69 -0
  57. package/skills/network-map/SKILL.md +61 -0
  58. package/skills/network-map/scripts/network_map.py +109 -0
  59. package/skills/personal-brand/SKILL.md +54 -0
  60. package/skills/personal-brand/references/post-pillars.md +66 -0
  61. package/skills/portfolio-site/SKILL.md +59 -0
@@ -0,0 +1,399 @@
1
+ #!/usr/bin/env python3
2
+ """Genera la presentacion DETALLADA de Claude Code Arcane (12 slides, 16:9)."""
3
+ import os
4
+ from pptx import Presentation
5
+ from pptx.util import Inches, Pt
6
+ from pptx.dml.color import RGBColor
7
+ from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
8
+ from pptx.enum.shapes import MSO_SHAPE
9
+
10
+ # ---------- Tema (paleta Arcane: indigo profundo + cian) ----------
11
+ BG = RGBColor(0x1E, 0x1B, 0x4B)
12
+ PANEL = RGBColor(0x2A, 0x25, 0x60)
13
+ PANEL2 = RGBColor(0x31, 0x2E, 0x81)
14
+ VIOLET = RGBColor(0x5B, 0x4F, 0xE8)
15
+ CYAN = RGBColor(0x22, 0xD3, 0xEE)
16
+ WHITE = RGBColor(0xF8, 0xFA, 0xFC)
17
+ LIGHT = RGBColor(0xE5, 0xE7, 0xEB)
18
+ MUTED = RGBColor(0x9C, 0xA3, 0xC4)
19
+ GREEN = RGBColor(0x34, 0xD3, 0x99)
20
+ AMBER = RGBColor(0xFB, 0xBF, 0x24)
21
+ PINK = RGBColor(0xF4, 0x72, 0xB6)
22
+ CODEBG = RGBColor(0x14, 0x11, 0x33)
23
+ FONT = "Calibri"
24
+ MONO = "Consolas"
25
+
26
+ prs = Presentation()
27
+ prs.slide_width = Inches(13.333)
28
+ prs.slide_height = Inches(7.5)
29
+ BLANK = prs.slide_layouts[6]
30
+ SW, SH = prs.slide_width, prs.slide_height
31
+
32
+
33
+ def slide():
34
+ s = prs.slides.add_slide(BLANK)
35
+ r = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, SW, SH)
36
+ r.fill.solid(); r.fill.fore_color.rgb = BG
37
+ r.line.fill.background(); r.shadow.inherit = False
38
+ return s
39
+
40
+
41
+ def rect(s, x, y, w, h, color, line=None, radius=False, line_w=1.0):
42
+ shp = MSO_SHAPE.ROUNDED_RECTANGLE if radius else MSO_SHAPE.RECTANGLE
43
+ sp = s.shapes.add_shape(shp, Inches(x), Inches(y), Inches(w), Inches(h))
44
+ if color is None:
45
+ sp.fill.background()
46
+ else:
47
+ sp.fill.solid(); sp.fill.fore_color.rgb = color
48
+ if line is None:
49
+ sp.line.fill.background()
50
+ else:
51
+ sp.line.color.rgb = line; sp.line.width = Pt(line_w)
52
+ sp.shadow.inherit = False
53
+ return sp
54
+
55
+
56
+ def txt(s, x, y, w, h, runs, align=PP_ALIGN.LEFT, anchor=MSO_ANCHOR.TOP,
57
+ space_after=4, line_spacing=1.0, font=FONT):
58
+ tb = s.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
59
+ tf = tb.text_frame; tf.word_wrap = True
60
+ tf.vertical_anchor = anchor
61
+ for i, para in enumerate(runs):
62
+ p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
63
+ p.alignment = align
64
+ p.space_after = Pt(space_after); p.space_before = Pt(0)
65
+ p.line_spacing = line_spacing
66
+ for (t, sz, col, bold) in para:
67
+ r = p.add_run(); r.text = t
68
+ r.font.size = Pt(sz); r.font.color.rgb = col
69
+ r.font.bold = bold; r.font.name = font
70
+ return tb
71
+
72
+
73
+ def badge(s, n):
74
+ c = s.shapes.add_shape(MSO_SHAPE.OVAL, Inches(12.55), Inches(6.85), Inches(0.42), Inches(0.42))
75
+ c.fill.solid(); c.fill.fore_color.rgb = VIOLET; c.line.fill.background(); c.shadow.inherit = False
76
+ tf = c.text_frame
77
+ p = tf.paragraphs[0]; p.alignment = PP_ALIGN.CENTER
78
+ r = p.add_run(); r.text = str(n)
79
+ r.font.size = Pt(12); r.font.bold = True; r.font.color.rgb = WHITE; r.font.name = FONT
80
+ tf.vertical_anchor = MSO_ANCHOR.MIDDLE
81
+
82
+
83
+ def footer(s):
84
+ txt(s, 0.55, 7.02, 6, 0.35, [[("Claude Code Arcane", 9, MUTED, False)]])
85
+
86
+
87
+ def kicker(s, text, color=CYAN):
88
+ rect(s, 0.55, 0.55, 0.12, 0.5, color)
89
+ txt(s, 0.8, 0.5, 11.5, 0.45, [[(text, 12.5, color, True)]])
90
+
91
+
92
+ def title(s, text, y=0.92, size=32):
93
+ txt(s, 0.78, y, 11.9, 0.9, [[(text, size, WHITE, True)]])
94
+
95
+
96
+ def chrome(s, n, kick, ttl, color=CYAN, tsize=32):
97
+ kicker(s, kick, color)
98
+ title(s, ttl, size=tsize)
99
+ badge(s, n); footer(s)
100
+
101
+
102
+ # ================= SLIDE 1 — Portada =================
103
+ s = slide()
104
+ rect(s, 0, 0, 0.25, 7.5, VIOLET)
105
+ rect(s, 0.25, 0, 0.08, 7.5, CYAN)
106
+ txt(s, 1.0, 1.55, 11.5, 0.6, [[("CLAUDE CODE", 20, CYAN, True)]])
107
+ txt(s, 1.0, 2.0, 11.5, 1.4, [[("Arcane", 84, WHITE, True)]])
108
+ txt(s, 1.05, 3.42, 11, 0.6, [[("Un gestor de paquetes de configuracion para Claude Code", 21, LIGHT, False)]])
109
+ txt(s, 1.05, 4.0, 11, 0.5, [[("Skills, agentes, hooks y reglas — instalados selectivamente por stack.", 14, MUTED, False)]])
110
+ metrics = [("322", "Skills"), ("86", "Agentes"), ("29", "Profiles"), ("19", "Rules"), ("16", "Hooks")]
111
+ mx, mw, gap = 1.0, 2.12, 0.18
112
+ for i, (num, lbl) in enumerate(metrics):
113
+ x = mx + i * (mw + gap)
114
+ rect(s, x, 4.95, mw, 1.4, PANEL, radius=True)
115
+ rect(s, x, 4.95, 0.09, 1.4, CYAN if i % 2 else VIOLET)
116
+ txt(s, x, 5.12, mw, 0.7, [[(num, 40, WHITE, True)]], align=PP_ALIGN.CENTER)
117
+ txt(s, x, 5.88, mw, 0.4, [[(lbl.upper(), 12, CYAN, True)]], align=PP_ALIGN.CENTER)
118
+ txt(s, 1.0, 6.7, 11, 0.4, [[("Presentacion tecnica + de negocio · Educabot", 12, MUTED, False)]])
119
+
120
+ # ================= SLIDE 2 — Indice / recorrido =================
121
+ s = slide()
122
+ chrome(s, 2, "RECORRIDO", "Que vamos a ver")
123
+ items = [
124
+ ("01", "El problema", "Por que la config de Claude no escala"),
125
+ ("02", "La idea", "npm, pero para capacidades de IA"),
126
+ ("03", "Arquitectura", "Como instala, mergea y deduplica"),
127
+ ("04", "Las 4 piezas", "Skills, Agents, Hooks, Rules"),
128
+ ("05", "Anatomia de una skill", "Frontmatter + markdown"),
129
+ ("06", "Profiles", "El sistema de combinacion LEGO"),
130
+ ("07", "Mecanismos avanzados", "Distribucion, update, worktrees"),
131
+ ("08", "Calidad", "Testing automatizado de skills"),
132
+ ("09", "Por que gana", "vs. las alternativas"),
133
+ ("10", "Trade-offs y cierre", "Honesto + casos reales"),
134
+ ]
135
+ positions = [(0.78, 2.0 + (i % 5) * 0.95, 0 if i < 5 else 1) for i in range(10)]
136
+ for (num, h, d), i in zip(items, range(10)):
137
+ col = 0 if i < 5 else 1
138
+ x = 0.78 + col * 6.15
139
+ y = 2.0 + (i % 5) * 0.95
140
+ rect(s, x, y, 5.85, 0.82, PANEL, radius=True)
141
+ txt(s, x + 0.25, y, 0.9, 0.82, [[(num, 22, VIOLET, True)]], anchor=MSO_ANCHOR.MIDDLE)
142
+ txt(s, x + 1.15, y + 0.1, 4.5, 0.4, [[(h, 14.5, CYAN, True)]])
143
+ txt(s, x + 1.15, y + 0.45, 4.6, 0.35, [[(d, 11, MUTED, False)]])
144
+
145
+ # ================= SLIDE 3 — El problema =================
146
+ s = slide()
147
+ chrome(s, 3, "POR QUE EXISTE", "El problema que resuelve")
148
+ problems = [
149
+ ("Configuracion manual", "Copiar .claude/ a mano en cada proyecto: repetitivo y diverge con el tiempo."),
150
+ ("Todo-o-nada", "Un mega-repo cargaria las 322 skills en CADA proyecto: mas tokens, mas ruido, mas latencia."),
151
+ ("Sin estandarizacion", "Cada dev configura su Claude distinto. No hay fuente de verdad compartida."),
152
+ ("Sin actualizacion", "Una mejora en una skill nunca llega a los proyectos que ya la copiaron."),
153
+ ]
154
+ y = 2.0
155
+ for h, d in problems:
156
+ rect(s, 0.78, y, 11.7, 0.95, PANEL, radius=True)
157
+ rect(s, 0.78, y, 0.1, 0.95, VIOLET)
158
+ txt(s, 1.05, y + 0.1, 3.4, 0.75, [[(h, 16, CYAN, True)]], anchor=MSO_ANCHOR.MIDDLE)
159
+ txt(s, 4.5, y + 0.1, 7.8, 0.75, [[(d, 13, LIGHT, False)]], anchor=MSO_ANCHOR.MIDDLE)
160
+ y += 1.08
161
+ txt(s, 0.78, 6.55, 11.8, 0.5,
162
+ [[("Falta una forma modular, versionada y compartible de configurar Claude Code.", 15, WHITE, True)]])
163
+
164
+ # ================= SLIDE 4 — La idea central =================
165
+ s = slide()
166
+ chrome(s, 4, "LA IDEA CENTRAL", "npm, pero para las capacidades de Claude Code")
167
+ txt(s, 0.78, 1.95, 11.7, 0.9,
168
+ [[("En vez de instalar librerias de codigo, instalas ", 16, LIGHT, False),
169
+ ("capacidades", 16, CYAN, True),
170
+ (": hacer commits, disenar APIs, correr un sprint, auditar seguridad — adaptadas a tu stack.", 16, LIGHT, False)]],
171
+ line_spacing=1.12)
172
+ rect(s, 0.78, 3.05, 11.7, 1.45, CODEBG, radius=True, line=VIOLET, line_w=1.5)
173
+ txt(s, 1.1, 3.22, 11, 0.35, [[("terminal", 11, MUTED, False)]], font=MONO)
174
+ txt(s, 1.1, 3.62, 11, 0.7,
175
+ [[("$ ", 24, CYAN, True), ("npx arcane install ", 24, WHITE, True),
176
+ ("backend-ts", 24, GREEN, True), ("+agile", 24, AMBER, True), ("+testing", 24, AMBER, True)]], font=MONO)
177
+ cols = [("backend-ts", "base", GREEN), ("+agile", "addon", AMBER), ("+testing", "addon", AMBER)]
178
+ cx = 0.78
179
+ for name, kind, col in cols:
180
+ rect(s, cx, 4.75, 3.0, 1.05, PANEL, radius=True)
181
+ txt(s, cx, 4.9, 3.0, 0.5, [[(name, 17, col, True)]], align=PP_ALIGN.CENTER)
182
+ txt(s, cx, 5.4, 3.0, 0.35, [[(kind.upper(), 11, MUTED, True)]], align=PP_ALIGN.CENTER)
183
+ cx += 3.25
184
+ txt(s, 0.78, 6.05, 11.7, 0.5, [[("base + addon + addon -> solo lo que ESE proyecto necesita.", 15, WHITE, True)]])
185
+
186
+ # ================= SLIDE 5 — Como funciona =================
187
+ s = slide()
188
+ chrome(s, 5, "ARQUITECTURA", "Como funciona la instalacion")
189
+ steps = [
190
+ ("1", "Resuelve el contenido", "GitHub -> cache local -> bundled (funciona offline)"),
191
+ ("2", "Carga core.yaml siempre", "21 skills base + 15 hooks + permisos de seguridad"),
192
+ ("3", "Mergea los profiles", "Combina los profiles pedidos con el separador +"),
193
+ ("4", "Deduplica", "Un skill repetido en varios profiles se copia una sola vez"),
194
+ ("5", "Genera .claude/", "settings.json + manifest + skills, agents, rules, hooks, docs"),
195
+ ]
196
+ y = 1.95
197
+ for num, h, d in steps:
198
+ rect(s, 0.78, y, 11.7, 0.82, PANEL, radius=True)
199
+ c = s.shapes.add_shape(MSO_SHAPE.OVAL, Inches(0.98), Inches(y + 0.16), Inches(0.5), Inches(0.5))
200
+ c.fill.solid(); c.fill.fore_color.rgb = VIOLET; c.line.fill.background(); c.shadow.inherit = False
201
+ ctf = c.text_frame; ctf.vertical_anchor = MSO_ANCHOR.MIDDLE
202
+ cp = ctf.paragraphs[0]; cp.alignment = PP_ALIGN.CENTER
203
+ cr = cp.add_run(); cr.text = num; cr.font.size = Pt(20); cr.font.bold = True
204
+ cr.font.color.rgb = WHITE; cr.font.name = FONT
205
+ txt(s, 1.75, y + 0.04, 4.0, 0.74, [[(h, 15.5, CYAN, True)]], anchor=MSO_ANCHOR.MIDDLE)
206
+ txt(s, 5.9, y + 0.04, 6.4, 0.74, [[(d, 12.5, LIGHT, False)]], anchor=MSO_ANCHOR.MIDDLE)
207
+ y += 0.93
208
+ txt(s, 0.78, 6.6, 11.7, 0.4,
209
+ [[("Resultado: el .claude/ del proyecto contiene exactamente lo necesario — nada mas.", 13, MUTED, True)]])
210
+
211
+ # ================= SLIDE 6 — 4 piezas =================
212
+ s = slide()
213
+ chrome(s, 6, "SEPARACION DE RESPONSABILIDADES", "Cuatro piezas, cuatro responsabilidades")
214
+ cards = [
215
+ ("Skills", "Acciones que Claude ejecuta", "/commit · /code-review · /sprint-plan", CYAN),
216
+ ("Agents", "Personas que Claude adopta", "backend-architect · game-designer", VIOLET),
217
+ ("Hooks", "Automatizacion invisible (eventos)", "valida commits · escanea secrets", GREEN),
218
+ ("Rules", "Estandares que Claude obedece", "\"Clean architecture en backend\"", AMBER),
219
+ ]
220
+ positions = [(0.78, 1.95), (6.93, 1.95), (0.78, 4.15), (6.93, 4.15)]
221
+ cw, ch = 5.6, 2.0
222
+ for (name, what, ex, col), (x, y) in zip(cards, positions):
223
+ rect(s, x, y, cw, ch, PANEL, radius=True)
224
+ rect(s, x, y, cw, 0.12, col)
225
+ txt(s, x + 0.3, y + 0.22, cw - 0.6, 0.5, [[(name, 23, col, True)]])
226
+ txt(s, x + 0.3, y + 0.82, cw - 0.6, 0.5, [[(what, 14, LIGHT, False)]])
227
+ txt(s, x + 0.3, y + 1.35, cw - 0.6, 0.5, [[(ex, 12, MUTED, True)]])
228
+ txt(s, 0.78, 6.45, 11.7, 0.5,
229
+ [[("Todo en Markdown + YAML: legible, diffeable en git, editable por cualquiera.", 14, WHITE, True)]])
230
+
231
+ # ================= SLIDE 7 — Anatomia de una skill =================
232
+ s = slide()
233
+ chrome(s, 7, "DEEP DIVE", "Anatomia de una skill")
234
+ # bloque de codigo
235
+ rect(s, 0.78, 1.95, 6.7, 4.55, CODEBG, radius=True, line=VIOLET, line_w=1.2)
236
+ txt(s, 1.0, 2.1, 6.3, 0.35, [[("skills/commit/SKILL.md", 11, MUTED, False)]], font=MONO)
237
+ code = [
238
+ [("---", 12.5, MUTED, False)],
239
+ [("name:", 12.5, PINK, True), (" commit", 12.5, LIGHT, False)],
240
+ [("description:", 12.5, PINK, True), (" \"Crea un commit", 12.5, GREEN, False)],
241
+ [(" siguiendo conventional commits...\"", 12.5, GREEN, False)],
242
+ [("category:", 12.5, PINK, True), (" workflow", 12.5, LIGHT, False)],
243
+ [("user-invocable:", 12.5, PINK, True), (" true", 12.5, AMBER, False)],
244
+ [("allowed-tools:", 12.5, PINK, True), (" Read, Bash", 12.5, LIGHT, False)],
245
+ [("model:", 12.5, PINK, True), (" haiku", 12.5, LIGHT, False), (" # opcional", 11, MUTED, False)],
246
+ [("---", 12.5, MUTED, False)],
247
+ [("", 6, MUTED, False)],
248
+ [("Review staged & unstaged changes", 12.5, CYAN, False)],
249
+ [("with git diff, suggest type/scope,", 12.5, CYAN, False)],
250
+ [("write a concise message...", 12.5, CYAN, False)],
251
+ ]
252
+ txt(s, 1.0, 2.5, 6.3, 3.9, code, space_after=2, font=MONO)
253
+ # explicacion lado derecho
254
+ rect(s, 7.75, 1.95, 4.72, 4.55, PANEL, radius=True)
255
+ txt(s, 8.0, 2.15, 4.3, 0.4, [[("Dos partes:", 16, WHITE, True)]])
256
+ fields = [
257
+ ("Frontmatter (YAML)", "Metadatos: nombre, tools permitidas, si es invocable, modelo a usar, agente asociado."),
258
+ ("Cuerpo (Markdown)", "Las instrucciones en lenguaje natural que Claude sigue al invocar la skill."),
259
+ ]
260
+ y = 2.7
261
+ for h, d in fields:
262
+ txt(s, 8.0, y, 4.3, 0.4, [[(h, 13.5, CYAN, True)]])
263
+ txt(s, 8.0, y + 0.38, 4.3, 0.9, [[(d, 12, LIGHT, False)]], line_spacing=1.05)
264
+ y += 1.5
265
+ txt(s, 8.0, 5.75, 4.3, 0.7,
266
+ [[("1 skill = 1 carpeta con un SKILL.md. Sin build, sin compilar.", 12.5, MUTED, True)]], line_spacing=1.05)
267
+
268
+ # ================= SLIDE 8 — Profiles =================
269
+ s = slide()
270
+ chrome(s, 8, "EL SISTEMA LEGO", "Profiles: combinar por stack")
271
+ txt(s, 0.78, 1.85, 11.7, 0.5,
272
+ [[("Cada profile es un YAML que agrupa skills, agentes, reglas y permisos. Se combinan con ", 13.5, LIGHT, False),
273
+ ("+", 14, AMBER, True), (".", 13.5, LIGHT, False)]])
274
+ # bases
275
+ rect(s, 0.78, 2.5, 5.7, 3.0, PANEL, radius=True)
276
+ txt(s, 1.0, 2.65, 5.3, 0.4, [[("BASE (elegis uno)", 13, GREEN, True)]])
277
+ bases = [("unity-dev", "25"), ("backend-ts", "33"), ("backend-go", "19"),
278
+ ("frontend", "14"), ("mobile", "12"), ("flutter / ios / android", "8")]
279
+ y = 3.15
280
+ for name, n in bases:
281
+ txt(s, 1.0, y, 4.2, 0.35, [[(name, 13, LIGHT, False)]])
282
+ txt(s, 5.3, y, 0.9, 0.35, [[(n, 13, CYAN, True)]], align=PP_ALIGN.RIGHT)
283
+ y += 0.37
284
+ # addons
285
+ rect(s, 6.63, 2.5, 5.85, 3.0, PANEL, radius=True)
286
+ txt(s, 6.85, 2.65, 5.4, 0.4, [[("ADDONS (combinas con +)", 13, AMBER, True)]])
287
+ addons = [("+agile", "10"), ("+testing", "11"), ("+infra", "17"),
288
+ ("+security", "5"), ("+marketing", "44"), ("+clevel / +regulatory", "28 / 13")]
289
+ y = 3.15
290
+ for name, n in addons:
291
+ txt(s, 6.85, y, 4.4, 0.35, [[(name, 13, LIGHT, False)]])
292
+ txt(s, 11.3, y, 0.9, 0.35, [[(n, 13, CYAN, True)]], align=PP_ALIGN.RIGHT)
293
+ y += 0.37
294
+ rect(s, 0.78, 5.7, 11.7, 0.85, PANEL2, radius=True)
295
+ txt(s, 1.0, 5.78, 11.3, 0.7,
296
+ [[("+ core (siempre): 21 skills universales + 15 hooks + seguridad. ", 13, WHITE, True),
297
+ ("Profiles combinados nunca duplican un skill.", 13, CYAN, True)]],
298
+ anchor=MSO_ANCHOR.MIDDLE, line_spacing=1.05)
299
+
300
+ # ================= SLIDE 9 — Mecanismos avanzados =================
301
+ s = slide()
302
+ chrome(s, 9, "PRODUCTION-GRADE", "Mecanismos que lo elevan")
303
+ feats = [
304
+ ("Distribucion hibrida", "Resuelve el contenido en cadena: GitHub -> cache local -> bundled en npm. Funciona incluso sin conexion.", CYAN),
305
+ ("Smart update (3-way merge)", "Compara base / tu version / upstream. Actualiza lo no tocado, preserva tus cambios, avisa conflictos.", VIOLET),
306
+ ("Worktree-aware", "En git worktrees comparte hooks/ y docs/ (symlink), pero copia skills/ por rama (pueden divergir).", GREEN),
307
+ ("Auto-release", "semantic-release lee los conventional commits: fix -> patch, feat -> minor. Publica a npm solo.", AMBER),
308
+ ]
309
+ positions = [(0.78, 1.95), (6.93, 1.95), (0.78, 4.3), (6.93, 4.3)]
310
+ cw, ch = 5.6, 2.15
311
+ for (h, d, col), (x, y) in zip(feats, positions):
312
+ rect(s, x, y, cw, ch, PANEL, radius=True)
313
+ rect(s, x, y, 0.1, ch, col)
314
+ txt(s, x + 0.32, y + 0.22, cw - 0.6, 0.5, [[(h, 17, col, True)]])
315
+ txt(s, x + 0.32, y + 0.78, cw - 0.62, 1.2, [[(d, 12.5, LIGHT, False)]], line_spacing=1.1)
316
+
317
+ # ================= SLIDE 10 — Calidad / testing =================
318
+ s = slide()
319
+ chrome(s, 10, "CONFIABILIDAD", "Las skills se testean")
320
+ txt(s, 0.78, 1.9, 11.7, 0.5,
321
+ [[("322 prompts hay que mantenerlos con calidad. Arcane trae un framework de QA self-contained: ", 13.5, LIGHT, False),
322
+ ("skills-selftest/", 13.5, CYAN, True)]])
323
+ cards = [
324
+ ("/skill-test static", "Chequeo estructural: frontmatter valido, paths, tools declaradas.", GREEN),
325
+ ("/skill-test spec", "Evaluacion de comportamiento contra casos de prueba esperados.", CYAN),
326
+ ("/skill-test audit", "Reporte de cobertura: que skills tienen specs y cuales faltan.", VIOLET),
327
+ ("/skill-improve", "Loop test -> diagnostica -> arregla -> re-testea -> mantiene o revierte.", AMBER),
328
+ ]
329
+ y = 2.55
330
+ for h, d, col in cards:
331
+ rect(s, 0.78, y, 11.7, 0.85, PANEL, radius=True)
332
+ rect(s, 0.78, y, 0.1, 0.85, col)
333
+ txt(s, 1.05, y + 0.08, 3.6, 0.7, [[(h, 15, col, True)]], anchor=MSO_ANCHOR.MIDDLE, font=MONO)
334
+ txt(s, 4.9, y + 0.08, 7.4, 0.7, [[(d, 12.5, LIGHT, False)]], anchor=MSO_ANCHOR.MIDDLE)
335
+ y += 0.98
336
+ txt(s, 0.78, 6.5, 11.7, 0.4,
337
+ [[("catalog.yaml = registro maestro · quality-rubric.md = criterios pass/fail por categoria.", 12.5, MUTED, True)]])
338
+
339
+ # ================= SLIDE 11 — Por que gana =================
340
+ s = slide()
341
+ chrome(s, 11, "DIFERENCIADORES", "Por que Arcane gana")
342
+ rect(s, 0.78, 1.95, 5.7, 0.52, PANEL2, radius=True)
343
+ rect(s, 6.63, 1.95, 5.85, 0.52, PANEL2, radius=True)
344
+ txt(s, 1.0, 1.98, 5.3, 0.45, [[("ALTERNATIVA", 12.5, MUTED, True)]], anchor=MSO_ANCHOR.MIDDLE)
345
+ txt(s, 6.85, 1.98, 5.4, 0.45, [[("COMO GANA ARCANE", 12.5, CYAN, True)]], anchor=MSO_ANCHOR.MIDDLE)
346
+ rows = [
347
+ ("Config a mano", "Un comando, versionado, reproducible"),
348
+ ("Mega-repo monolitico", "Selectivo por profile + dedup (menos tokens)"),
349
+ ("Copiar config entre proyectos", "Smart update con three-way merge"),
350
+ ("Claude \"vanilla\"", "Hooks + rules + 86 agentes especializados"),
351
+ ]
352
+ y = 2.58
353
+ for a, b in rows:
354
+ rect(s, 0.78, y, 5.7, 0.68, PANEL, radius=True)
355
+ rect(s, 6.63, y, 5.85, 0.68, PANEL, radius=True)
356
+ txt(s, 1.0, y + 0.04, 5.3, 0.6, [[(a, 13.5, LIGHT, False)]], anchor=MSO_ANCHOR.MIDDLE)
357
+ txt(s, 6.85, y + 0.04, 5.4, 0.6, [[(b, 13, WHITE, True)]], anchor=MSO_ANCHOR.MIDDLE)
358
+ y += 0.78
359
+ rect(s, 0.78, y + 0.05, 11.7, 0.68, VIOLET, radius=True)
360
+ txt(s, 0.78, y + 0.08, 11.7, 0.6,
361
+ [[("Configuracion de IA tratada como software: versionada, modular, testeable y distribuida.", 13.5, WHITE, True)]],
362
+ align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
363
+
364
+ # ================= SLIDE 12 — Trade-offs + cierre =================
365
+ s = slide()
366
+ chrome(s, 12, "BALANCE Y CIERRE", "Trade-offs honestos")
367
+ # pros
368
+ rect(s, 0.78, 1.95, 5.7, 3.05, PANEL, radius=True)
369
+ rect(s, 0.78, 1.95, 5.7, 0.55, RGBColor(0x14, 0x3D, 0x2E), radius=True)
370
+ txt(s, 1.02, 1.98, 5.3, 0.5, [[("FORTALEZAS", 14, GREEN, True)]], anchor=MSO_ANCHOR.MIDDLE)
371
+ pros = ["Eficiencia de tokens", "Un comando, cero friccion",
372
+ "Reproducible (manifest)", "Estandarizacion de equipo",
373
+ "Auto-update sin pisar cambios", "Testeable (skills-selftest)"]
374
+ y = 2.62
375
+ for p in pros:
376
+ txt(s, 1.02, y, 5.3, 0.4, [[("+ ", 13, GREEN, True), (p, 12.5, LIGHT, False)]])
377
+ y += 0.39
378
+ # contras
379
+ rect(s, 6.63, 1.95, 5.85, 3.05, PANEL, radius=True)
380
+ rect(s, 6.63, 1.95, 5.85, 0.55, RGBColor(0x4A, 0x39, 0x12), radius=True)
381
+ txt(s, 6.87, 1.98, 5.4, 0.5, [[("COSTOS", 14, AMBER, True)]], anchor=MSO_ANCHOR.MIDDLE)
382
+ cons = ["Mantener 322 skills con calidad", "Skills = prompts -> no deterministas",
383
+ "Depende de la API de Claude Code", "Curva: saber que profiles combinar"]
384
+ y = 2.62
385
+ for c in cons:
386
+ txt(s, 6.87, y, 5.5, 0.5, [[("! ", 13, AMBER, True), (c, 12.5, LIGHT, False)]])
387
+ y += 0.52
388
+ # CTA
389
+ rect(s, 0.78, 5.25, 11.7, 1.45, VIOLET, radius=True)
390
+ txt(s, 0.78, 5.4, 11.7, 0.5,
391
+ [[("Configuracion de IA, modular y versionada — un comando para empezar.", 17, WHITE, True)]],
392
+ align=PP_ALIGN.CENTER)
393
+ txt(s, 0.78, 5.95, 11.7, 0.5, [[("npx arcane install backend-ts+agile", 21, WHITE, True)]],
394
+ align=PP_ALIGN.CENTER, font=MONO)
395
+
396
+ out = os.path.join(os.path.dirname(os.path.abspath(__file__)), "arcane-overview-12.pptx")
397
+ prs.save(out)
398
+ print("OK ->", out)
399
+ print("Slides:", len(prs.slides._sldIdLst))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-arcane",
3
- "version": "1.1.1",
3
+ "version": "1.3.0",
4
4
  "description": "Skills, agents, hooks and rules for Claude Code — installable via npx arcane",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,54 @@
1
+ name: backend-dotnet
2
+ description: "Backend .NET — ASP.NET Core (.NET 10), Vertical Slice / Clean Architecture, EF Core + PostgreSQL, JWT + Identity, testing. Best practices priorizadas por impacto."
3
+ type: base
4
+
5
+ skills:
6
+ # .NET-specific (nuevas)
7
+ - dotnet-scaffold
8
+ - dotnet-best-practices
9
+ - dotnet-architecture
10
+ # API & data
11
+ - database
12
+ - database-indexing
13
+ - data-migrations
14
+ - api-design
15
+ - api-docs
16
+ - api-versioning
17
+ - caching-strategy
18
+ - webhooks
19
+ - rate-limiting
20
+ # Auth & security
21
+ - auth-strategy
22
+ - jwt-strategy
23
+ - oauth-setup
24
+ - rbac-abac
25
+ - audit-log
26
+ # Ops & quality
27
+ - testing
28
+ - contract-testing
29
+ - deps-audit
30
+ - env-sync
31
+ - observability
32
+ - performance
33
+ - async-ops
34
+ - ci-cd-setup
35
+
36
+ rules:
37
+ universal:
38
+ - backend-code
39
+ - api-code
40
+ - dotnet-code
41
+ - migration-code
42
+ gamedev:
43
+ []
44
+
45
+ agents:
46
+ - engineering
47
+
48
+ permissions:
49
+ allow:
50
+ - "Bash(dotnet *)"
51
+ - "Bash(docker ps*)"
52
+ - "Bash(docker images*)"
53
+ deny:
54
+ []
@@ -0,0 +1,35 @@
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"
3
+ type: addon
4
+
5
+ skills:
6
+ - job-hunt
7
+ - master-profile
8
+ - cv-tailor
9
+ - cv-ats-export
10
+ - linkedin-optimize
11
+ - portfolio-site
12
+ - job-search
13
+ - cover-letter
14
+ - cold-outreach
15
+ - interview-prep
16
+ - network-map
17
+ - personal-brand
18
+
19
+ rules:
20
+ universal:
21
+ []
22
+ gamedev:
23
+ []
24
+
25
+ agents:
26
+ []
27
+
28
+ permissions:
29
+ allow:
30
+ - "Bash(python *cv_export.py*)"
31
+ - "Bash(python3 *cv_export.py*)"
32
+ - "Bash(python *network_map.py*)"
33
+ - "Bash(python3 *network_map.py*)"
34
+ deny:
35
+ []
@@ -10,6 +10,7 @@ skills:
10
10
  - map-systems
11
11
  - asset-spec
12
12
  - game-audit
13
+ - install-mcp
13
14
  - quick-design
14
15
  - ux-design
15
16
  - design-system
@@ -12,6 +12,7 @@ skills:
12
12
  - release-checklist
13
13
  - patch-notes
14
14
  - onboard
15
+ - install-mcp
15
16
  - scaffold-unity
16
17
  - unity-game-architecture
17
18
  - map-systems
@@ -0,0 +1,64 @@
1
+ ---
2
+ paths:
3
+ - "**/*.cs"
4
+ - "**/*.csproj"
5
+ - "**/Program.cs"
6
+ - "**/*.Tests.cs"
7
+ - "src/**"
8
+ - "tests/**"
9
+ ---
10
+
11
+ # .NET / C# Code Rules
12
+
13
+ Reglas production-ready para ASP.NET Core (.NET 10), ordenadas por impacto. Catálogo completo (40 reglas, 10 categorías) + ejemplos incorrecto/correcto: skill `dotnet-best-practices`. Estructura de proyecto: skill `dotnet-architecture`.
14
+
15
+ ## CRITICAL — Arquitectura & DI
16
+
17
+ - **Organizar por feature (Vertical Slice)** o por capas con dependencias hacia adentro (Clean) — nunca un `Services/` + `Controllers/` global gigante.
18
+ - **Endpoints/controllers finos** — traducen HTTP ↔ request, llaman al handler y dan shape a la respuesta. Cero lógica de negocio.
19
+ - **`DbContext` es Unit of Work + Repository** — no envolverlo en `IRepository<T>` / `IUnitOfWork` genérico (indirección sin valor que tapa `Include`/proyecciones).
20
+ - **Constructor injection (primary constructors) siempre.** Nunca service locator ni `BuildServiceProvider()` manual en `Program.cs`.
21
+ - **Lifetimes correctos** — `Scoped` para `DbContext`/handlers, `Singleton` solo si es stateless; nunca inyectar `Scoped` en `Singleton` (captured dependency).
22
+ - **`<Nullable>enable</Nullable>`** + warnings as errors; cero `#nullable disable` para silenciar.
23
+
24
+ ## HIGH — Async, Error handling & Security
25
+
26
+ - **Async end-to-end.** Nunca `.Result`/`.Wait()`/`.GetAwaiter().GetResult()` (deadlocks / thread-pool starvation). Sin `async void` salvo event handlers.
27
+ - **Propagar `CancellationToken`** desde el endpoint hasta EF Core y llamadas HTTP. Sin fire-and-forget sin manejo de error.
28
+ - **Errores vía `ProblemDetails` (RFC 7807)** — `AddProblemDetails()` + `IExceptionHandler` global. Nunca filtrar stack traces. Validación → `ValidationProblemDetails`.
29
+ - **Result pattern para fallos esperados**, excepciones solo para lo excepcional. Sin `catch` vacíos.
30
+ - **JWT de vida corta + refresh**, secretos en user-secrets/Key Vault (no en `appsettings.json`). Authorization por **policies declarativas**, no checks manuales de roles.
31
+ - **Rate limiting** con el middleware built-in (`AddRateLimiter`). HTTPS/HSTS. No loguear data sensible.
32
+
33
+ ## HIGH — Performance & Data (EF Core)
34
+
35
+ - **Evitar N+1** — `Include` o proyección a DTO con `Select`. Nunca acceder a relaciones en un loop.
36
+ - **`AsNoTracking()`** en lecturas read-only. `AsSplitQuery()` para `Include` grandes (evita explosión cartesiana).
37
+ - **Migraciones versionadas** (`dotnet ef migrations add` / `MigrateAsync()`); nunca `EnsureCreated()` en prod.
38
+ - **Transacciones para operaciones multi-step**; `EnableRetryOnFailure` para resiliencia de conexión (Npgsql).
39
+ - **Caching estratégico** (`HybridCache`/output caching) con TTL e invalidación apropiada.
40
+
41
+ ## MEDIUM — API, Testing & DevOps
42
+
43
+ - **DTOs en el borde** (records) — nunca exponer entidades EF como respuestas HTTP.
44
+ - **API versioning** (`Asp.Versioning`) para cambios breaking; OpenAPI con `Microsoft.AspNetCore.OpenApi`.
45
+ - **`TypedResults`** en minimal APIs para status codes correctos y testeables.
46
+ - **Tests con xUnit**; integración con `WebApplicationFactory` + Postgres real (Testcontainers). No mockear `DbContext` ni usar el in-memory provider (miente sobre comportamiento relacional).
47
+ - **Structured logging (Serilog JSON)** + health checks (liveness/readiness). Graceful shutdown vía `IHostApplicationLifetime`.
48
+ - **Config por entorno** (`IOptions<T>`, `appsettings.{Environment}.json`) — nada hardcodeado.
49
+
50
+ ## Anti-Patterns
51
+
52
+ - `IRepository<T>` / `IUnitOfWork` genérico sobre EF Core
53
+ - Lógica de negocio en controllers/endpoints
54
+ - `.Result` / `.Wait()` (sync-over-async) → deadlocks
55
+ - `EnsureCreated()` contra una DB de producción
56
+ - Service locator / `BuildServiceProvider()` en runtime
57
+ - Devolver entidades EF crudas como respuesta HTTP
58
+ - N+1 queries por falta de `Include`/proyección
59
+ - `Domain` referenciando `Infrastructure` / EF Core (dependencia hacia afuera)
60
+ - Forzar Clean Architecture en un CRUD simple (sobre-ingeniería)
61
+
62
+ ---
63
+
64
+ _Derivado de [github/awesome-copilot](https://github.com/github/awesome-copilot) (dotnet-best-practices), [dotnet/skills](https://github.com/dotnet/skills) y [ardalis/CleanArchitecture](https://github.com/ardalis/CleanArchitecture). Condensado al formato Arcane._
@@ -0,0 +1,65 @@
1
+ ---
2
+ name: cold-outreach
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
+ argument-hint: "[contact-note | recruiter + company]"
5
+ category: "career"
6
+ user-invocable: true
7
+ allowed-tools: Read, Glob, Grep, Write, Edit, WebFetch
8
+ ---
9
+
10
+ # Cold Outreach — Job-seeker → Recruiter / Hiring Manager
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`) — el ángulo es conseguir una conversación o un referido, sin sonar a spam ni a desesperación.
13
+
14
+ ## Cuándo usar cada variante
15
+
16
+ | Situación | Mensaje |
17
+ |-----------|---------|
18
+ | Recruiter posteó un rol | Mensaje corto con fit + interés explícito |
19
+ | Hiring manager / futuro lead | Mensaje de valor: qué resolvés que a su equipo le importa |
20
+ | Pedir un referido a alguien de la empresa | Cálido, bajo compromiso, fácil de decir que sí |
21
+ | Networking sin rol abierto | Curiosidad genuina + algo en común, sin pedir nada todavía |
22
+ | Follow-up post-aplicación | Recordatorio con valor, no "¿alguna novedad?" |
23
+
24
+ ## Principios
25
+
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–125 palabras. La connection note: <300 caracteres.
28
+ - **Una pregunta / un CTA.** Bajá la fricción de responder.
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
+ - **Sin paredes de texto, sin CV adjunto en el primer toque** (salvo que lo pidan).
31
+ - **Respetá el "no".** Un follow-up, máximo dos. Nunca insistir agresivo.
32
+
33
+ ## Estructura de un primer mensaje
34
+
35
+ 1. **Gancho personal** (1 línea): por qué *a esta persona*.
36
+ 2. **Quién sos + fit** (1–2 líneas): rol + el logro más relevante para ellos.
37
+ 3. **CTA suave** (1 línea): ¿15 min para charlar? / ¿abierto a una intro? / dejé mi aplicación, encantado de dar contexto.
38
+
39
+ ## Secuencia de follow-up post-aplicación
40
+
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
+
45
+ Cada follow-up debe tener un **gancho propio** y leerse solo, sin depender de los anteriores.
46
+
47
+ ## Proceso
48
+
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) — WebFetch del perfil público si hay URL.
51
+ 3. Elegir variante + canal.
52
+ 4. Draftear mensaje + 1 variante de apertura.
53
+ 5. Registrar en `05-Contactos/` (historial de interacciones) y planificar el follow-up.
54
+
55
+ > Nota: Claude no accede a tu LinkedIn ni envía mensajes — redacta para que vos copies/pegues y registres la interacción.
56
+
57
+ ## Idioma
58
+
59
+ Espejá el idioma de la persona/empresa. Inglés por default para roles internacionales.
60
+
61
+ Ver `references/recruiter-playbook.md` para plantillas por situación y la psicología de por qué responden.
62
+
63
+ ## Handoff
64
+
65
+ Pedí aprobación (approval) antes de escribir en `05-Contactos/`. Cuando el mensaje está READY para copiar/pegar y el follow-up agendado, prepará la conversación con `/interview-prep` si hay respuesta.