usage-tracker — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited usage-tracker (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Gestiona el sistema de logging de consumo local de Claude Code y permite analizar el coste por petición del usuario.
| Archivo | Cuándo cargar |
|---|---|
references/pricing.md | MANDATORY al calcular o explicar costes en € |
references/log-usage.sh | MANDATORY en install si el hook no existe |
references/usage-report.sh | MANDATORY en install si el script no existe |
| No cargar los scripts | Para report, top-requests y status — solo se ejecutan |
Cada mensaje del usuario dispara múltiples tool calls en secuencia. El log registra cada tool call con el campo request = último mensaje del usuario que lo originó. Esto permite agrupar todos los tool calls de una petición y calcular su coste total.
Usuario: "revisa el módulo delsol"
└─ Read delsol.module → 1.200 tok ┐
└─ Grep hook_order → 80 tok │ mismo "request"
└─ Read DelsolService.php → 2.400 tok │ → coste total: 4.980 tok
└─ Bash phpcs delsol/ → 1.300 tok ┘Para ver el coste por petición:
cat ~/.claude/usage.jsonl | python3 -c "
import json, sys
from collections import defaultdict
req = defaultdict(lambda: {'tok':0,'tools':[],'ts':''})
for line in sys.stdin:
try:
d = json.loads(line.strip())
r = d.get('request','—')[:80]
req[r]['tok'] += d.get('tok_total',0)
req[r]['ts'] = d.get('ts','')[:10]
req[r]['tools'].append(d.get('tool','?'))
except: pass
print(f'{'Tokens':>8} {'Tools':>5} Petición')
print('-'*80)
for r, v in sorted(req.items(), key=lambda x: -x[1]['tok'])[:15]:
print(f'{v[\"tok\"]:>8,} {len(v[\"tools\"]):>5} {r}')
"Antes de ejecutar, evalúa:
offset/limit en Read si solo necesitas una sección concreta.Ficheros grandes leídos completos Un Read de 3.000 líneas = ~15.000 tokens de output. Si la petición lo lee dos veces (para entender y luego editar), el coste se duplica. Identificar en el log peticiones con múltiples Read del mismo archivo.
Contexto acumulado de conversación El hook captura el tool call aislado, pero Claude envía toda la historia con cada petición. Una conversación de 40 mensajes puede añadir 80.000 tokens invisibles por petición. El log subestima más a medida que avanza la conversación — las primeras peticiones del día son las más fiables.
Agent calls con subagentes Un Agent tool call lanza una conversación completa internamente. Si el log muestra un Agent con 500 tokens, el coste real puede ser 20.000+. Son el mayor punto ciego del sistema.
Bash con output masivo git log, find, cat archivo_grande pueden devolver miles de líneas. El output del tool son tokens. Una petición con varios Bash de output masivo puede ser 10x más cara de lo que parece.
Skills cargadas en contexto Cada SKILL.md activo añade tokens de overhead fijo por petición durante esa sesión. El log no lo captura.
¿Es un Agent call?
└─ Sí → Coste real = 10-100x lo que muestra el log. No analizar más.
¿Hay múltiples Read del mismo archivo?
└─ Sí → Se leyó para entender y se releyó para editar.
Optimización: usar offset/limit en el segundo Read.
¿Hay Bash con mucho tok_out?
└─ Sí → Output masivo (logs, git, find).
Optimización: añadir | head -50 o filtrar antes de leer.
¿La petición está tarde en una conversación larga?
└─ Sí → El contexto acumulado domina el coste real.
Optimización: nueva conversación para tareas independientes.
¿Muchas herramientas para una petición simple?
└─ Sí → Claude exploró antes de actuar (Glob→Read→Read→Edit).
Normal en primera exploración; evitar en peticiones repetidas.| Tipo de petición | Coste log | Coste real | Causa |
|---|---|---|---|
| "revisa este archivo" (1.000 LOC) | Alto | Alto | Read masivo |
| "ejecuta el lint" | Bajo | Bajo | Bash corto |
| "analiza todo el módulo" | Alto | Muy alto | Agent probable |
| "arregla este bug" en conv. larga | Medio | Muy alto | Contexto acumulado |
| "cambia este string" | Muy bajo | Bajo | Edit preciso |
| "busca dónde se usa X" | Bajo | Bajo | Grep eficiente |
report [hoy|semana|mes|all] [proyecto]MANDATORY: Cargar references/pricing.md si se explican costes en €.
~/.claude/usage-report.sh hoy
~/.claude/usage-report.sh semana OltexEl reporte incluye la sección "Por petición (top 20 más costosas)" de forma automática — muestra cada mensaje del usuario con su nº de tools, tokens totales, coste y resumen de herramientas (Edit×5, Bash×3…). No hace falta ejecutar top-requests por separado.
top-requests [hoy|semana]Ejecutar el snippet Python de "coste por petición" con el filtro de fecha. Mostrar las 15 peticiones más caras del período con sus tokens y herramientas usadas.
installMANDATORY: Cargar references/log-usage.sh y references/usage-report.sh.
ls -la ~/.claude/log-usage.sh ~/.claude/usage-report.shreferences/ con Write toolchmod +x ~/.claude/log-usage.sh ~/.claude/usage-report.shsettings.json: buscar "$HOME/.claude/log-usage.sh" en hooks.PostToolUsepython3 -c "import json,os; json.load(open(os.path.expanduser('~/.claude/settings.json')))"tail -1 ~/.claude/usage.jsonlError recovery para `install`:
settings.json queda corrupto tras la edición: restaurar desde ~/.claude/settings.json.bak si existe; si no, reconstruir la sección hooks manualmente con Edit y revalidar con python3.chmod falla (permiso denegado): verificar propietario con ls -la y usar sudo chmod solo si es necesario.references/ con Write tool sobreescribiendo el archivo destino.status# Hook activo
python3 -c "import json,os; d=json.load(open(os.path.expanduser('~/.claude/settings.json'))); print('Hook OK' if any('log-usage' in str(h) for h in d.get('hooks',{}).get('PostToolUse',[])) else 'Hook AUSENTE')"
# Última entrada
tail -1 ~/.claude/usage.jsonl | python3 -c "import sys,json; d=json.loads(sys.stdin.read()); print(d.get('ts','')[:19], d.get('tool',''), d.get('label','')[:50])"
# Hace cuánto
python3 -c "
import json,os; from datetime import datetime,timezone
last=json.loads(open(os.path.expanduser('~/.claude/usage.jsonl')).readlines()[-1])
dt=datetime.fromisoformat(last['ts'].replace('Z','+00:00'))
age=(datetime.now(timezone.utc)-dt).seconds//60
print(f'Última entrada hace {age} min — {\"OK\" if age<60 else \"POSIBLE PROBLEMA\"}')" 2>/dev/null || echo "Log vacío"Si usage-report.sh falla con errores de parsing JSON:
# 1. Contar líneas totales
grep -c '' ~/.claude/usage.jsonl
# 2. Encontrar líneas rotas
python3 -c "
import json, os
with open(os.path.expanduser('~/.claude/usage.jsonl')) as f:
for i, line in enumerate(f, 1):
try:
json.loads(line.strip())
except:
print(f'Línea {i} rota: {line[:80]}')
"
# 3. Extraer solo líneas válidas
python3 -c "
import json, sys, os
with open(os.path.expanduser('~/.claude/usage.jsonl')) as f:
valid = [l for l in f if l.strip()]
for l in valid:
try: json.loads(l); print(l, end='')
except: pass
" 2>/dev/null
# Si hay pocas líneas rotas: archivar y regenerar el log limpio
cp ~/.claude/usage.jsonl ~/.claude/usage-backup-$(date +%Y%m%d).jsonl
grep -v '^$' ~/.claude/usage.jsonl | python3 -c "
import sys, json
for l in sys.stdin:
try: json.loads(l); print(l, end='')
except: pass
" > /tmp/usage_clean.jsonl && mv /tmp/usage_clean.jsonl ~/.claude/usage.jsonl¿Existe usage.jsonl?
├─ No → Hook nunca disparó
│ → Verificar settings.json (comando status)
│ → chmod +x ~/.claude/log-usage.sh
│ → Reiniciar Claude Code para recargar settings.json
└─ Sí, pero no crece
├─ Hook ausente en settings.json → install
├─ settings.json JSON inválido → reparar JSON
├─ python3 no disponible → hook falla silenciosamente
└─ Script sin permisos → chmod +xSession IDs poco fiables: PPID se reutiliza entre sesiones. Usar CLAUDE_SESSION_ID si está disponible; si no, agrupar entradas separadas <30 min del mismo proyecto como una sesión.
Subestimación sistémica no lineal: La subestimación no crece linealmente con la conversación — crece de forma cuadrática. A mensaje 5: ~20% de subestimación. A mensaje 20: ~60%. A mensaje 40+: ~80-90%. El motivo: el contexto acumulado se envía completo en cada petición, y ese contexto también crece a cada mensaje. Las primeras peticiones de cada sesión son las únicas realmente fiables; usar ~/.claude/usage-report.sh hoy comparando solo las primeras entradas del día para calibrar.
Agent calls son el mayor punto ciego: Los tokens internos del subagente son invisibles. Nunca comparar proyectos con distinta proporción de Agent calls.
Ruido de procesos externos: UUIDs en el reporte = Paperclip u otros procesos. Filtrar por proyecto.
settings.json directamente sin validar JSON después — falla silenciosamente.usage.jsonl — archivar: cp ~/.claude/usage.jsonl ~/.claude/usage-$(date +%Y%m%d).jsonlsettings.json — duplicaría cada entrada del log.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.