¿Qué hace llm-scan?
Esta skill mapea cada sitio de llamada a un LLM y el registro de uso de un repositorio en work/<repo>/routes.json. Es de solo lectura: nunca edita, formatea, confirma ni ejecuta nada dentro del repositorio objetivo.
0. configuración
- Detecta qué agente de codificación eres: Claude Code o Codex (o cualquier otro). Lee solo el archivo coincidente,
delegation/claude.mdodelegation/codex.md, en este paquete. Indica qué paso va a un ayudante rápido y barato y cuál se queda contigo. - Establece
<pack>como la carpeta que contienescripts/calc.py(dos niveles por encima de este archivo) y<repo>como el nombre de la carpeta del repositorio objetivo. Crea<pack>/work/<repo>/; todas las salidas van allí. Nunca escribas dentro del repositorio objetivo.
1. encuentra cada sitio de llamada
Busca en todo el repositorio (omite node_modules, .venv, dist, build, .git, archivos de bloqueo). Cuenta todos estos:
- Llamadas SDK: cualquier llamada a una biblioteca cliente que envía un prompt a un modelo (chat, messages, completions, responses, embeddings, helpers de streaming, frameworks de agente).
- Llamadas CLI a subprocesos: una CLI de modelo o agente ejecutada desde el código en modo no interactivo (un flag de impresión como
-p,exec,--prompt), incluidos workers cálidos de larga duración y pipes de stream-json. - Llamadas HTTP: solicitudes directas a una URL de API de modelo, una puerta de enlace, un proxy o un endpoint autoalojado.
- Modelos de decisión, compuerta, clasificador, enrutador, reranker y juez, incluso si son pequeños o baratos. También son llamadas a LLM.
- Llamadas de calentamiento, keepalive y health-check que golpean un modelo: regístralas como rutas (a menudo no tienen uso en los logs; ver
usage_gaps). - Llamadas en pruebas, scripts, notebooks y trabajos cron: enuméralas, pero márcalas con
"live": falsesi nunca se ejecutan en producción. - Llamadas a modelos que no son LLM (speech-to-text, text-to-speech, OCR, servicios de visión facturados por minuto o por imagen): están fuera del alcance para precios. Enuméralas con
"kind": "non_llm"para que el informe pueda decir que se vieron y no se valoraron.
Busca importaciones de cliente, nombres de host de API, cadenas model= / "model":, max_tokens, stream, cache_control y lanzamientos de subprocesos de CLIs de modelo. Luego abre cada coincidencia y lee la función alrededor.
2. registra cada ruta
Escribe una entrada por cada sitio de llamada. El id de la ruta es relative/path.ext:function_name; para un método, relative/path.ext:Class.method; usa <module> si es de nivel superior. Usa la misma ortografía de id en todas partes (routes.json, filas, informe).
| campo | significado |
|---|---|
id | file:function o file:Class.method |
kind | sdk, cli, http, non_llm |
provider | como lo muestra el código, si no null |
model | la cadena del modelo exactamente como está escrita, o la clave de configuración / variable de entorno que lo establece (entonces también model_source). Cuando el modelo de una ruta varía en tiempo de ejecución, escribe "varies" y nombra la configuración o fuente en model_source |
streaming | true / false / null |
cache_markers | explicit (el código marca puntos de caché de prompt), implicit (sin marcas, pero un prefijo estable, proceso cálido o valor predeterminado del proveedor puede almacenarlo en caché), none (nada sugiere almacenamiento en caché), unknown |
max_tokens | el número, o null si no está configurado |
retries | cuenta y dónde (SDK predeterminado, wrapper, bucle), o 0 |
user_waits | true si una persona está esperando la respuesta (chat, voz, UI en vivo); false para batch, background, cron; "unknown" si no puedes saberlo |
decision_model | true para compuertas, enrutadores, clasificadores, jueces |
decision_shaped | true si la respuesta es un veredicto pequeño que alimenta una rama de código (un enum, un booleano, una etiqueta, una puntuación) y la ruta se ejecuta por evento o por elemento; false si la respuesta es texto libre o salida estructurada larga; "unknown" si no puedes saberlo. Regístralo para cada ruta; calc también lo detecta desde los logs (p50 de salida de 5 tokens o menos en 50+ llamadas) |
tools | dónde se construyen y envían las definiciones de herramientas o funciones (file:function, y cuántas se envían por llamada si el código lo muestra), o null si la ruta no envía ninguna. Solo hechos; los números provienen de los logs |
live | true; false si solo es prueba; "unknown" si no puedes saberlo |
stateless | true si cada llamada es independiente (una compuerta o clasificador por evento que no envía turnos anteriores); false si una conversación o memo crece a través de llamadas; "unknown" |
notes | una línea corta, solo hechos que viste |
Usa null (o "unknown" donde la tabla lo permita) cuando no puedas saberlo. Nunca adivines un valor.
3. encuentra los registros de uso
Encuentra dónde la aplicación ya registra el uso (tokens, costo, latencia, tiempo hasta el primer token, éxito). Busca archivos de log, JSONL, CSV, SQLite o tablas de base de datos, llamadas de tracing y métricas, y campos de uso del proveedor guardados de las respuestas. Para cada uno, registra:
- la ruta o tabla y el formato;
- los NOMBRES de los campos, nunca los valores;
- si algún campo contiene texto de prompt o respuesta (
has_text_fields); - qué ids de ruta cubre.
No abras los valores de los logs más allá de las primeras líneas necesarias para aprender los nombres de los campos, y no copies ningún texto de ellos.
También observa, solo por NOMBRE de campo, si los logs registran definiciones de herramientas o uso de herramientas por llamada (un conteo de herramientas enviadas, el tamaño de las definiciones de herramientas en tokens, un conteo de llamadas a herramientas en la respuesta); llm-capture convierte esto en tools_defined, tool_schema_tokens y tool_calls. Si los logs carecen de ellos, dilo en usage_gaps.
También registra usage_gaps: notas cortas en texto plano (una línea cada una, solo hechos) donde ocurren llamadas pero los logs no contienen uso de tokens o los números registrados no se pueden confiar tal cual. Ejemplos: "las llamadas de calentamiento en la ruta X se registran sin uso", "el costo registrado es un total acumulado por proceso", "la ruta Y no está registrada en absoluto". Los conteos son bienvenidos ("visto N veces") cuando los leas solo a partir de nombres de campo y cuentas.
4. escribe routes.json
Escribe <pack>/work/<repo>/routes.json:
{
"repo": "<repo>",
"root": "<ruta absoluta del repositorio objetivo>",
"scanned": "<YYYY-MM-DD>",
"routes": [
{"id": "path/file.py:Class.method", "kind": "cli", "provider": null, "model": "<string>", "model_source": null,
"streaming": true, "cache_markers": "implicit", "max_tokens": null, "retries": 0,
"user_waits": true, "decision_model": false, "decision_shaped": false, "tools": null, "live": true, "stateless": false, "notes": ""},
{"id": "path/stt.py:transcribe", "kind": "non_llm", "live": true, "notes": "speech-to-text, no valorado"}
],
"usage_logs": [
{"path": "<ruta relativa o tabla>", "format": "jsonl", "fields": ["<solo nombres>"],
"has_text_fields": true, "covers_routes": ["path/file.py:Class.method"]}
],
"usage_gaps": ["<una nota corta cada una>"]
}
5. finalizar
Informa al usuario en pocas líneas cuántas rutas encontraste, cuáles son las orientadas al usuario, qué registros de uso existen y cualquier usage_gaps. No estimes costos o velocidades aquí; los números provienen solo de scripts/calc.py.
Luego ejecuta la siguiente skill, llm-capture.