Estoy pagando $15 por millón de tokens para escribir ‘fix: typo’

| Última modificación: 4 de mayo de 2026 | Tiempo de Lectura: 7 minutos
Premios Blog KeepCoding 2025

Co-Fundador de KeepCoding

Ayer escribí un commit message con Claude Code. El diff era un cambio de una línea: un typo en un comentario. Claude Opus leyó el diff, pensó durante dos segundos, y generó fix: correct typo in auth comment. Para eso consumió unos 800 tokens de entrada y 30 de salida, a $15 y $75 por millón respectivamente. Coste: una fracción de centavo. Pero multiplica eso por 40 commits al día, 250 días al año, en una empresa con 200 desarrolladores usando coding agents, y la fracción de centavo se convierte en miles de dólares gastados en la tarea intelectual equivalente a poner tiritas.

El problema no es que Opus sea caro. El problema es que los coding agents no distinguen entre tareas de $0.001 y tareas de $0.10. Todo pasa por el mismo modelo. Generar un commit message, clasificar una issue, validar un formato — todo va al modelo grande al mismo coste que diseñar una arquitectura de microservicios. Es el equivalente de contratar a un cirujano para poner tiritas.

Los números

Vamos a hacer las cuentas con los precios de Claude Opus 4 (la generación anterior, la que la mayoría sigue usando en producción):

Tarea Tokens entrada Tokens salida Coste
Commit message (diff pequeño) ~800 ~30 $0.014
Clasificar una issue ~500 ~50 $0.011
Validar formato de commit ~300 ~20 $0.006
Standup summary ~2000 ~200 $0.045

Ninguna de estas tareas necesita un modelo con 2 trillones de parámetros y capacidad de razonamiento multi-paso. Son tareas de clasificación y generación con restricciones fuertes. El equivalente de ordenar cartas por color.

Con el modelo on-device de Apple Intelligence (3B parámetros, incluido en macOS 26): coste $0.00, latencia ~300ms, sin red, sin API key.

foundation-hooks

foundation-hooks es un conjunto de 4 binarios Swift que usan el framework Foundation Models de Apple para automatizar tareas de desarrollo que no justifican un modelo cloud:

Binario Función Hook git
fm-commit-msg Genera commit messages convencionales a partir del diff prepare-commit-msg
fm-validate-msg Valida formato y sugiere correcciones commit-msg
fm-lql-create Clasifica y crea issues en Linear via lql CLI
fm-lql-standup Genera standup summary desde git log + issues CLI

Los cuatro comparten el mismo patrón: definir un struct Swift con @Generable, alimentar el modelo con contexto mínimo, obtener salida estructurada en milisegundos.

Instalación:

git clone https://github.com/frr/foundation-hooks
cd foundation-hooks
make build && make install-hooks REPO=/path/to/your/repo

A partir de ese momento, cada git commit genera automáticamente un mensaje convencional. El hook está instalado en 11 repositorios de producción desde hace dos semanas.

Cómo funciona: @Generable y constrained decoding

Esta es la parte que merece atención técnica. @Generable no es «pedirle al modelo que devuelva JSON y cruzar los dedos». Es constrained decoding — el modelo literalmente no puede generar tokens que violen el schema.

El mecanismo

  1. @Generable es un macro Swift que genera un JSON Schema en tiempo de compilación a partir del struct.
  2. El framework inyecta ese schema en el prompt como especificación de formato de respuesta.
  3. Durante la inferencia, en cada paso de decodificación, se aplica token masking: los tokens del vocabulario que producirían una salida inválida según el schema se enmascaran (probabilidad 0 en el softmax).
  4. El modelo solo puede elegir entre tokens válidos.

Apple describe esto como «guided generation» en la documentación de WWDC25. Es la misma técnica que OpenAI usa con response_format: json_schema y que Anthropic aplica en tool use. La diferencia: Apple lo integra en el sistema de tipos de Swift. Defines el struct, el compilador genera el schema, el runtime lo aplica en inferencia. Type safety end-to-end.

Los tres niveles de restricción

@Generable
struct CommitMessage {
    // Nivel 1: restricción DURA — enum efectivo
    // Token masking activo: solo "fix", "feat", "refactor", etc.
    // Los tokens que formarían "bug" o "update" tienen probabilidad 0.
    @Guide(.anyOf(["fix", "feat", "refactor", "test", "docs", "chore", "style"]))
    var type: String

    // Nivel 2: restricción SUAVE — como un system prompt para este campo
    // El modelo tiende a seguirlo pero no está forzado.
    @Guide(description: "Scope of the change, e.g. auth, ui, db. One word, lowercase.")
    var scope: String

    // Nivel 3: sin restricción — string libre, el modelo decide
    var subject: String
}

La analogía: anyOf es un dropdown, description es un input con placeholder, y un campo sin Guide es un textarea vacío. La diferencia entre los tres no es de grado sino de mecanismo. El primero opera a nivel de tokens (el modelo no puede salirse), el segundo opera a nivel de prompt (el modelo tiende a seguirlo), el tercero no tiene guía.

Esto es relevante porque el caso de uso de los hooks es exactamente el escenario donde la restricción dura brilla. Un commit type tiene que ser uno de 7 valores. No hay ambigüedad, no hay creatividad, no hay razonamiento. Es clasificación pura. Un modelo de 3B parámetros con constrained decoding lo hace tan bien como uno de 200B. La diferencia es que uno tarda 300ms y es gratis, y el otro tarda 2 segundos y cuesta dinero.

El código completo de un hook

Este es fm-commit-msg, el hook de prepare-commit-msg. Son 106 líneas de Swift, sin dependencias externas:

import Foundation
import FoundationModels

@Generable
struct CommitMessage {
    @Guide(description: "Type of change")
    @Guide(.anyOf(["fix", "feat", "refactor", "test", "docs", "chore", "style"]))
    var type: String

    @Guide(description: "Scope of the change, e.g. auth, ui, db, api. One word, lowercase.")
    var scope: String

    @Guide(description: "Imperative summary of the change, max 50 chars, lowercase, no period")
    var subject: String
}

guard SystemLanguageModel.default.isAvailable else {
    exit(0) // No Apple Intelligence — exit silently, user writes their own
}

Tres cosas que destacar:

  1. Graceful degradation: si Apple Intelligence no está disponible (Mac sin Apple Silicon, modelo no descargado), el hook sale con código 0 y git continúa normalmente. Nunca bloquea.

  2. No inventa: el modelo recibe git diff --cached --stat y un patch truncado a 3000 caracteres. Suficiente para clasificar y resumir, insuficiente para confabular.

  3. No reemplaza al humano: el mensaje se escribe al fichero de commit con comentarios git (#), así que git commit lo muestra en el editor. El usuario puede modificarlo o descartarlo.

La generación:

let session = LanguageModelSession(instructions: """
    You generate git commit messages in conventional commits format.
    Focus on WHY the change was made, not WHAT changed.
    The subject must be imperative mood, lowercase, no period, max 50 chars.
    """)

let result = try await session.respond(to: prompt, generating: CommitMessage.self)
let msg = result.content
let message = "\(msg.type)(\(msg.scope)): \(msg.subject)"

session.respond(to:generating:) devuelve una instancia de CommitMessage, no un String. No hay parsing. No hay regex. No hay try? JSONDecoder().decode(...). El struct es el contrato y el compilador lo garantiza.

Integración con issue tracking: fm-lql-create

El mismo patrón funciona para issue tracking. fm-lql-create clasifica una descripción en lenguaje natural y crea una issue en Linear via lql, un CLI de Linear escrito en Rust:

@Generable
struct IssueClassification {
    @Guide(.anyOf(["bug", "feature", "improvement", "task", "chore"]))
    var type: String

    @Guide(.anyOf(["urgent", "high", "medium", "low", "none"]))
    var priority: String

    @Guide(description: "Clean, professional issue title. Max 80 chars.")
    var title: String

    @Guide(description: "One-line description for the issue body")
    var description: String
}

Uso:

$ fm-lql-create "auth token refresh crashes when expired"
PROD | high | bug | TOK: Auth: token refresh crashes on expiry
Token refresh fails silently when the OAuth token has expired, causing auth loop.

Press Enter to create, Ctrl-C to cancel:

El modelo local clasifica la issue en ~500ms: tipo bug, prioridad high, título limpio, descripción de una línea. Luego lql create la crea en Linear. El --dry-run flag muestra la propuesta sin ejecutar nada.

Dos campos con anyOf (type, priority) garantizan que la clasificación es válida. No puede devolver «priority: very important» ni «type: bugfix». Los tokens están enmascarados. Dos campos con description (title, description) dan libertad controlada al modelo.

Antes y después

Paso Con coding agent (Opus) Con foundation-hooks
Generar commit message ~2s, ~800 tokens, ~$0.014 ~300ms, 0 tokens, $0.00
Validar formato ~1.5s, ~300 tokens, ~$0.006 ~200ms, 0 tokens, $0.00
Clasificar issue ~2s, ~500 tokens, ~$0.011 ~500ms, 0 tokens, $0.00
Generar standup ~3s, ~2000 tokens, ~$0.045 ~800ms, 0 tokens, $0.00
Requiere red Si No
Requiere API key Si No
Funciona en avion No Si

Los tiempos del modelo local son mediciones reales en un MacBook Pro M4 Pro. No son benchmarks sintéticos.

Lo que no puede hacer

El modelo on-device de Apple es un modelo de 3B parámetros con una ventana de contexto de 4096 tokens. Tiene límites claros:

  • Diffs largos: por encima de ~3000 caracteres de patch, el contexto se trunca. Para refactors masivos que tocan 20 ficheros, el modelo solo ve el resumen estadístico (--stat), no el patch completo. El commit message será genérico pero correcto en formato.

  • Decisiones arquitectónicas: «Should I use a protocol or a concrete type here?» es una pregunta que necesita contexto de proyecto, historia del codebase, y razonamiento multi-paso. Eso sigue siendo territorio de modelos grandes.

  • Generación de código: foundation-hooks no genera código. Genera metadata sobre código: commit messages, clasificaciones, resúmenes. La frontera es clara: si la tarea es «escribir» algo que un humano revisará, usa el modelo grande. Si la tarea es «etiquetar» algo que un humano ya escribió, usa el modelo local.

  • Solo macOS 26+ con Apple Silicon: no funciona en Linux, no funciona en Macs Intel. Para equipos heterogéneos, el hook sale silenciosamente y el usuario escribe su propio mensaje.

Instalación

# Prerequisitos: macOS 26, Xcode 26, Apple Intelligence activado
git clone https://github.com/frr/foundation-hooks
cd foundation-hooks
make build

# Instalar hooks en un repo especifico
make install-hooks REPO=/path/to/your/repo

# Instalar binarios CLI en ~/.local/bin
make install-lql

# Instalar hooks en todos los repos conocidos (editar Makefile para ajustar la lista)
make install-all

El Makefile copia los binarios compilados directamente a .git/hooks/. No hay runtime, no hay daemon, no hay configuración. Si el binario está en el hook, funciona. Si no quieres AI en un commit, git commit --no-verify.

La tesis

Los coding agents son herramientas extraordinarias para tareas que requieren razonamiento complejo. Pero el modelo de precios actual no distingue entre complejidad. Cada interacción con el modelo — desde diseñar una arquitectura hasta escribir «fix: typo» — pasa por el mismo pipeline, al mismo coste, con la misma latencia.

La solución no es dejar de usar coding agents. Es dejar de usarlos para todo. Las tareas de clasificación, validación y generación con restricciones fuertes son resolubles con un modelo de 3B parámetros corriendo en local. El hardware ya está en tu máquina. El framework ya está en el sistema operativo. Solo falta el código que los conecte.

foundation-hooks son 400 líneas de Swift que conectan esos puntos. make install-hooks REPO=. y cada commit genera su propio mensaje, cada issue se clasifica sola, cada standup se escribe en 800ms. Sin red, sin tokens, sin coste.

El cirujano puede dejar de poner tiritas.


Read this article in English.

Noticias recientes del mundo tech


¡CONVOCATORIA ABIERTA!

Desarrollo de apps móviles ios & Android

Full Stack Bootcamp

Clases en Directo | Profesores en Activo | Temario 100% actualizado

Descárgate también el informe de tendencias en el mercado laboral 2026.

Fórmate con planes adaptados a tus objetivos y logra resultados en tiempo récord.
KeepCoding Bootcamps
Resumen de privacidad

Esta web utiliza cookies para que podamos ofrecerte la mejor experiencia de usuario posible. La información de las cookies se almacena en tu navegador y realiza funciones tales como reconocerte cuando vuelves a nuestra web o ayudar a nuestro equipo a comprender qué secciones de la web encuentras más interesantes y útiles.