PTENES
MÓDULO 5.1

🏛️ El estándar Agent Skills, el problema y la arquitectura de polyskill

Antes del CLI, el concepto. Por qué existe polyskill, qué problema resuelve y cómo su arquitectura de 3 piezas (IR + adaptadores + CLI) escala a nuevos runtimes sin reescrituras.

7
Temas
45
Minutos
Avanz.
Nivel
Teoría
Tipo

🎯Lo que obtienes aquí

Mapa mental completo de polyskill: por qué existe, qué problema aborda y cómo funciona internamente. Sin esto, el CLI de la próxima clase se convierte en «comandos memorizados». Con esto, es una arquitectura clara.

Contenido detallado

1

📐 La especificación abierta Agent Skills (agentskills.io)

Estándar originado en Anthropic y liberado como especificación abierta. Hoy lo adoptan más de 40 herramientas. Define el formato canónico de una skill: SKILL.md + frontmatter YAML + cuerpo en markdown + convención de carpetas.

Los 4 pilares: en qué coinciden TODOS los runtimes

1
Nombre del archivo: SKILL.md — no inventes variaciones
2
Frontmatter YAML con al menos name e description
3
Cuerpo en Markdown estándar
4
Carpetas convencionadas: scripts/, references/, assets/

💡Por qué esto importa

Todo lo que escribes dentro de estos 4 pilares funciona en cualquier runtime compatible. Todo lo que queda AFUERA (allowed-tools, backtick-bang, openai.yaml, model override) te ata a un runtime específico; ahí está el trabajo de polyskill.

Conceptos clave

Especificación abierta
agentskills.io
Más de 40 runtimes
Adopción amplia
4 pilares
Núcleo portable
Extras = lo atan todo
Fuera de los 4 = runtime
2

😩 El problema — mantener dos skills divergentes

Sin entender el problema, polyskill parece excesivo. Esta es la historia que vive TODO el mundo que usa ambos runtimes:

D1

Día 1 — Crea una skill en Claude

Funciona perfecto. Estás contento.

D2

Día 2 — Copia/adapta para Codex

Muévela a .agents/skills/, elimina backtick-bang, ajusta la descripción. Funciona en ambos. Sigues conforme.

S2

Semana 2 — Mejora la de Claude (olvídate de la de Codex)

Encuentra un caso de uso nuevo, agrega instrucciones en Claude. Olvida propagarlas.

S3

Semana 3 — Mejora la de Codex (olvídate de la de Claude)

Estaba en Codex, vio un bug y lo corrigió. Se olvida de llevarlo a Claude.

M1

Mes 1 — Dos skills DIFERENTES

Las versiones divergieron en 4 puntos. No recuerdas cuál es la correcta. Cada vez que mejoras una, descartas la mejora de la otra. Fuente de verdad ambigua.

💀Costos invisibles de la deriva

  • • Tiempo perdido decidiendo «qué versión es la buena»
  • • Los bugs vuelven (lo corregiste en una versión, lo olvidaste en la otra)
  • • La función funciona en un agente, pero no en el otro
  • • El equipo se confunde (la skill se comporta de forma diferente)
  • • La documentación queda desactualizada en ambos lados

Conceptos clave

Drift orgánico
Inevitable sin tooling
Fork accidental
Versiones divergentes
Source ambigua
¿Cuál conviene?
Costo cognitivo
Decisión constante
3

💡 La idea central — una fuente, varios destinos

Polyskill resuelve el problema como un compilador resuelve el "código portable". Escribes la skill UNA sola vez en el formato canónico portable (definition.md). El polyskill compila para dist/claude/ e dist/codex/, cada uno optimizado para el runtime de destino.

Analogía directa: Babel/TypeScript

TypeScript:
source.ts → tsc → source.js (ES5) + source.js (ES2020)
Babel:
source.jsx → babel → source.js (target: ie11) + source.js (modern)
Polyskill:
definition.md → polyskill build → dist/claude/SKILL.md + dist/codex/SKILL.md

La misma metáfora: fuente canónica, compilación selectiva por destino, output optimizado.

Cómo queda la estructura

minha-skill/
├── definition.md          ← SOURCE canônica (você edita aqui)
├── scripts/
├── references/
├── assets/
└── dist/                  ← OUTPUTS (gerados pelo polyskill build)
    ├── claude/
    │   └── minha-skill/
    │       └── SKILL.md  ← versão Claude (com allowed-tools, backtick-bang...)
    └── codex/
        └── minha-skill/
            ├── SKILL.md  ← versão Codex (sem bang, description front-loaded)
            └── agents/
                └── openai.yaml  ← sidecar gerado automaticamente

🎯El «momento ajá»

Nunca editas dist/. Solo edita definition.md. Ejecuta polyskill build. O dist/ refleja. Ejecuta polyskill install. Ambos runtimes tienen la versión más reciente. Una única fuente de verdad.

Conceptos clave

Source canónica
definition.md
Compilación
polyskill build
dist/ generada
No editar a mano
Optimización/objetivo
Por adaptador
4

🧱 Las 3 piezas — IR, adapters, CLI

Por dentro, polyskill tiene tres piezas. Al entender esto, ves que agregar Gemini/Cursor/Copilot es UN archivo — el adapter. No reescribas.

🏛️

1. IR (Representación Interna)

Versión neutral de todo lo que una skill necesita ser, SIN atarse a un runtime específico. Es el esperanto de polyskill.

🔌

2. Adaptadores

Un archivo TypeScript por runtime. Cada adapter implementa parse() + emit() + validate(). Instalar → es compatible. Quitar → desaparece.

⚡

3. CLI

Lo que ejecutas en la terminal. Orquesta los adapters mediante el registry. No conoce los detalles del runtime: le pregunta al adapter.

Arquitectura visual

┌──────────────────┐
│ definition.md │ ← TÚ editas
└────────┬─────────┘
│
▼
┌──────────────────┐ ┌─ portable adapter ─┐
│ Parse (portable)│ ──▶│ parse() / emit() │
└────────┬─────────┘ └────────────────────┘
│
▼
┌──────────────────┐
│ IR (neutral) │ ← representación interna
└────────┬─────────┘
│ dividir por target
├──────────────┬──────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│claude adapter│ │codex adapter │ │gemini adapter│ ← 1 archivo cada uno
│ emit() │ │ emit() │ │ emit() │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
▼ ▼ ▼
dist/claude/ dist/codex/ dist/gemini/

La interfaz Adapter

interface Adapter {
  name: string;

  // Lê o formato do runtime e devolve IR
  parse(path: string): IR;

  // Pega IR e escreve no formato do runtime
  emit(ir: IR, outputDir: string): void;

  // Roda regras específicas do runtime (lint)
  validate(ir: IR): ValidationResult;
}

// Registrar é literalmente uma linha:
register(new CodexAdapter());

🚀Por qué esto escala

Cuando Gemini CLI gane tracción, alguien implementará src/adapters/gemini.ts con parse/emit/validate, registra en el registry, abre un PR. Polyskill gana soporte para Gemini sin cambiar una línea del core. Lo mismo para Cursor, Copilot, lo-que-venga.

Conceptos clave

IR neutra
Sin ataduras al runtime
parse+emit+validate
Contrato del adapter
Patrón Registry
Plugin dinámico
Open core
Adaptar mediante PR
5

🔁 Round-trip — Claude ↔ portable ↔ Codex

Adapter "lee Y escribe". Puedes importar una skill existente de Claude (--from claude), convertirlo en portable y luego emitirlo para ambos. No hace falta empezar desde cero.

Flujos de round-trip

# Caso 1: empezaste en Claude y quieres que sea portable
~/.claude/skills/x/ ──▶ claude.parse() ──▶ IR ──▶ portable.emit() ──▶ ./x/definition.md
# Caso 2: empezaste en Codex y quieres que sea portable
~/.agents/skills/x/ ──▶ codex.parse() ──▶ IR ──▶ portable.emit() ──▶ ./x/definition.md
# Caso 3: tienes algo portable y lo quieres para ambos
./x/definition.md ──▶ portable.parse() ──▶ IR ──▶ claude.emit() + codex.emit()

Importación Claude → portable

$ polyskill import \
  ~/.claude/skills/x \
  --from claude

Lee SKILL.md + scripts + references. Genera definition.md preservándolo todo.

Importación Codex → portable

$ polyskill import \
  ~/.agents/skills/x \
  --from codex

Lee SKILL.md + sidecar openai.yaml. Normaliza a portable.

Lossless cuando sea posible, lossy cuando sea necesario

El round-trip conserva casi todo:

  • ✓ scripts/, references/, assets/ pasan intactos en ambos sentidos
  • ✓ Conserva el frontmatter portable (name, description)
  • ✓ Conserva el cuerpo en markdown

Las cosas específicas del runtime se convierten en marcadores en la IR:

  • ⚠️ Backtick-bang de Claude → IR lo marca como "dynamic injection" → al emitir para Codex se convierte en prosa
  • ⚠️ Sidecar openai.yaml de Codex → IR lo marca como "mcp deps" + "branding" → al emitir para Claude se convierte en allowed-tools

Conceptos clave

Bidireccional
Lee Y escribe
--from claude/codex
Flag de origen
Directorios lossless
scripts/refs/assets
Lossy semántico
Bang → prosa
6

🛡️ Política de drift — el seguro contra pisar cambios

Cada vez que haces un build, polyskill calcula el hash de los archivos de output. En el siguiente build, si algún archivo de destino se editó a mano fuera de polyskill, el build ABORTA con un error. Tú decides.

El flujo de drift

1.
polyskill build → genera dist/claude/x/SKILL.md, guarda el hash en .polyskill-hashes
2.
Editas a mano ~/.claude/skills/x/SKILL.md (ajuste específico)
3.
Días después: polyskill build de nuevo
4.
Polyskill compara el hash: desajuste detectado. Aborta con un mensaje claro.
5.
Eliges: --force (sobrescribe, se pierde el ajuste) O polyskill reconcile (inspecciona, decide).

✓ Por qué es seguro

  • • Nunca sobrescribe tu trabajo silenciosamente
  • • El drift se VE, no se oculta
  • • Siempre tienes la opción de force O reconcile
  • • Las ediciones en producción se pueden detectar en el próximo build

✗ Sin una política de control de divergencias sería…

  • • El ajuste manual desaparecería en la siguiente compilación
  • • Nunca lo sabrías (sin error)
  • • La confianza en la herramienta bajaría
  • • De todos modos volverías al mantenimiento manual

Ejemplo de output

$ polyskill build
✗ Drift detected!

The following targets have been modified outside polyskill:
  - ~/.claude/skills/x/SKILL.md (last hash: a3f9...; current: 8d2b...)

Options:
  - Run `polyskill build --force` to overwrite (loses local edits)
  - Run `polyskill reconcile` to inspect and merge

Build aborted.

Conceptos clave

Archivo hash
.polyskill-hashes
No silent loss
Aborta antes
--force
Sobrescritura opt-in
reconcile
Fusión interactiva
7

🦜 La meta-skill — polyskill como skill

Detalle poético: el polyskill si se distribuye usando a sí mismo. Se ofrece como skill instalable en ambos runtimes. La invocas en lenguaje natural; la skill llama al CLI por debajo y traduce tu pedido en comandos.

🔷 Claude Code

/polyskill convierte mi skill
y-compare para que funcione en ambos
runtimes

Skill recibe NL y lo traduce a:

$ polyskill import \
    ~/.claude/skills/y-compare \
    --from claude
$ polyskill build

🟣 Codex

$polyskill converte minha skill
y-compare pra funcionar nos dois
runtimes

La misma skill, la misma traducción:

$ polyskill import \
    ~/.agents/skills/y-compare \
    --from codex
$ polyskill build

Rutas de instalación — A vs B

Camino A — arrastrar y soltar

Copia skill/dist/claude/polyskill para ~/.claude/skills/ e skill/dist/codex/polyskill para ~/.agents/skills/. Sin CLI. Solo funciona la metahabilidad; los comandos que necesita ejecutar fallan.

Camino B — source + CLI

Clona el repo, npm install && npm run build && npm link. CLI completo en el PATH. Para crear tus propias skills, B es obligatorio.

💡El dogfooding completo

Polyskill resuelve el problema de las "skills entre runtimes" usando una skill entre runtimes generada por sí misma. Si la metaskill funciona en ambos runtimes, polyskill demuestra que sirve. Si falla en uno, demuestra lo contrario. Honestidad arquitectónica.

Conceptos clave

Meta-skill
Polyskill como skill
NL interface
Sin tener que memorizar flags
Camino A vs B
Sin CLI / con
Uso interno
Usa la propia herramienta

🎯Resumen del módulo

✓
Agent Skills es una especificación abierta con 4 pilares portables — SKILL.md, name+description, body en markdown, directorios convencionales.
✓
El drift sin herramientas es inevitable — una semana basta para que diverjan.
✓
Source canónica → destinos compilados — analogía directa con Babel/TypeScript.
✓
3 piezas: IR + Adapters + CLI — agregar un runtime requiere UN archivo.
✓
Round-trip bidireccional — empieza desde Claude o Codex y llega a ambos.
✓
Política de drift = hash + reconciliación — nunca sobrescribe en silencio.
✓
La meta-skill usa polyskill en su propio desarrollo — usa su propio formato para distribuirse.

Siguiente módulo:

5.2 — CLI polyskill en la práctica (init, import, build, install, validate, reconcile)