20260911 #3 — Anatomía de un skill

Leí por dentro el skill deep-research de Claude Code para entender por qué un solo archivo da un resultado tan completo: cómo se escribe un prompt y cómo se arma un skill, con su código como ejemplo.

La investigación de la tesis no arrancó con una pregunta de investigación. Arrancó con una sorpresa: corrí deep-research para relevar el estado del arte de una línea candidata y volvió un informe que no esperaba de una sola corrida —27 fuentes, 123 afirmaciones extraídas, 25 verificadas y de esas 18 confirmadas y 7 refutadas—, con resumen ejecutivo, caveats y preguntas abiertas. Lo que más me llamó la atención no fue el volumen (de los 109 agentes ya hablé en la nota anterior) sino que todo eso salía de un solo skill. Quise ver cómo estaba hecho.

No fue fácil de encontrar: no vive en .claude/skills/ ni en ~/.claude. Está compilado dentro del binario de Claude Code como un workflow bundled, y un comentario del código cuenta su origen: "Ported from bughunter architecture". Son 349 líneas de JavaScript. Leerlas fue la investigación.

Cómo se hace un prompt

Adentro hay tres prompts, y los tres siguen la misma forma: un rol en el título, el contexto (la pregunta original más el insumo puntual), una tarea como checklist numerado, un criterio de decisión explícito y el formato de salida. El verificador es el más claro:

const VERIFY_PROMPT = (claim, v) =>
  "## Adversarial Claim Verifier (voter " + (v + 1) + "/3)\n\n" +
  "Be SKEPTICAL. Try to REFUTE this claim. ≥2/3 refutations kill it.\n\n" +
  "## Claim under review\n\"" + claim.claim + "\"\n" +
  "**Supporting quote:** \"" + claim.quote + "\"\n\n" +
  "## Checklist\n" +
  "1. Is the claim actually supported by the quote, or is it an overreach?\n" +
  "2. WebSearch for contradicting evidence.\n" +
  "3. Is the source quality sufficient for the claim's strength?\n" +
  "4. Is the claim outdated?\n" +
  "5. Is this a marketing claim / cherry-picked benchmark / forum speculation?\n\n" +
  "**refuted=false** ONLY if: well-supported, current, and source quality matches claim strength.\n" +
  "Default to refuted=true if uncertain.\n\nStructured output only. Evidence MUST be specific."

Es exactamente el marco que uso cuando reviso un prompt propio —rol, contexto, tarea, formato, restricciones—, pero con dos detalles que no suelo poner: el criterio de decisión está escrito como regla (refuted=false solo si…) y el empate se resuelve por defecto hacia el lado conservador ("Default to refuted=true if uncertain"). Un prompt que no dice qué hacer ante la duda deja esa decisión al modelo, y ahí es donde aparecen las respuestas prolijas pero infundadas.

Cómo se hace un skill

Un skill es más que un prompt largo. Lo que vi en el archivo se ordena en seis piezas:

1. Metadata de disparo. El meta declara nombre, descripción y las cinco fases, pero la clave es whenToUse: es lo que el modelo lee para decidir si invocar el skill, e incluye una instrucción previa —si la pregunta está subespecificada, hacer dos o tres aclaraciones antes de arrancar.

2. Constantes de tuning al tope. Nada de números mágicos enterrados en el código:

const VOTES_PER_CLAIM = 3
const REFUTATIONS_REQUIRED = 2
const MAX_FETCH = 15
const MAX_VERIFY_CLAIMS = 25

3. Un schema por agente. Cada uno de los cinco tipos de agente devuelve JSON validado contra un schema. Eso es lo que hace componible el pipeline: la salida de uno es la entrada tipada del siguiente.

4. Prompts como funciones. SEARCH_PROMPT(angle), FETCH_PROMPT(source, angle), VERIFY_PROMPT(claim, v): reciben el insumo y devuelven el texto. El prompt no se copia, se instancia.

5. Orquestación explícita. Búsqueda y descarga van en pipeline(): cada ángulo pasa a bajar sus fuentes apenas termina, sin esperar a los demás. Antes de verificar hay una barrera —y el comentario lo dice: "Barrier here is intentional"— porque el pool de afirmaciones tiene que estar completo para rankearlo. Después, parallel() anidado: 25 afirmaciones × 3 votos.

6. Diseño defensivo. Cada salida temprana (sin afirmaciones, todo refutado, síntesis fallida) devuelve un resultado útil con stats en vez de una excepción. Un voto null cuenta como abstención, no como pase libre:

const survives = valid.length >= REFUTATIONS_REQUIRED && refuted < REFUTATIONS_REQUIRED

Y el resultado final trae agentCalls: el skill calcula su propio costo (1 + ángulos + fuentes + claims × 3 + 1). Los 109 salieron de ahí.

Recortar el patrón

La prueba de que entendí el patrón fue reutilizarlo. Un par de corridas de la tesis se cortaron por límite de sesión antes de verificar, y en vez de repetirlas enteras escribí reverify-linea-c: mismo meta, mismas constantes, mismo schema de veredicto y el mismo verificador de tres votos, pero sin Scope, Search ni Fetch —esas fases las reemplazó un array de 22 afirmaciones ya extraídas. Todo el esqueleto heredado, un array propio. Las 22 volvieron confirmadas.

Lo que me llevo: un buen skill no es un prompt largo, es un prompt corto y bien formado, instanciado muchas veces por una orquestación que sabe dónde esperar y dónde no, y que mide lo que gasta. Y se lee en una tarde.

Tags: cómo escribir un prompt · cómo escribir un skill · deep-research · workflow DSL · verificación adversarial

Comentarios

Suscribirse

Dejá tu mail y te aviso cuando publique algo nuevo.

Te vamos a mandar un email cuando publique algo nuevo. Podés darte de baja cuando quieras desde el link que incluye cada envío. Más detalle en privacidad.