<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[JoeDayz]]></title><description><![CDATA[Community Guy | Java Champion | AWS Architect | Software Architect]]></description><link>https://joedayz.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/64a79aba336591d2a1481aae/cb9ccb81-1315-42f8-92ba-e67b6328de97.gif</url><title>JoeDayz</title><link>https://joedayz.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 28 Oct 2026 05:40:37 GMT</lastBuildDate><atom:link href="https://joedayz.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Jev vs KCP: no es un versus]]></title><description><![CDATA[En corto: no elijas uno. Hacen trabajos distintos. Jev —o un modelo de decisión similar— puede tomar un input y producir una decisión estructurada: una…]]></description><link>https://joedayz.hashnode.dev/jev-vs-kcp-no-es-un-versus</link><guid isPermaLink="true">https://joedayz.hashnode.dev/jev-vs-kcp-no-es-un-versus</guid><category><![CDATA[joedayz]]></category><category><![CDATA[kcp]]></category><category><![CDATA[jev]]></category><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Wed, 23 Sep 2026 15:18:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/c6f53aab-9d3e-4814-ba95-83b2122046ed.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>En corto:</strong> no elijas uno. Hacen trabajos distintos.</p>
<p><strong>Jev</strong> —o un modelo de decisión similar— puede tomar un input y producir una decisión estructurada: una categoría, un score, una probabilidad o una opción de un conjunto cerrado.</p>
<p><strong>KCP</strong> no clasifica ese texto. Su función está más cerca de declarar qué conocimiento, habilidades, procedimientos y reglas son válidos, cuáles están vigentes y bajo qué condiciones pueden utilizarse.</p>
<p>Y hay una tercera pieza que no conviene olvidar:</p>
<blockquote>
<p><strong>Una decisión no es lo mismo que una autorización, y una confianza no es lo mismo que una evidencia.</strong></p>
</blockquote>
<p>Si los ponemos al mismo nivel, parece que la IA aprueba un crédito o una póliza.</p>
<p>No necesariamente.</p>
<p>Primero están las reglas y el contexto autorizado. Después puede venir una decisión estructurada. Luego una política puede determinar qué hacer con ella. Y finalmente debe quedar evidencia de lo ocurrido.</p>
<p><strong>Un</strong> <code>0.82</code> <strong>no es una firma.</strong></p>
<p>Jev: <a href="https://jevai.net/es/">https://jevai.net/es/</a></p>
<p>KCP: <a href="https://github.com/Cantara/knowledge-context-protocol">https://github.com/Cantara/knowledge-context-protocol</a></p>
<h2>1. Cuatro preguntas, no cuatro productos que se pelean</h2>
<p>Cuando hablamos de AI Agents aparecen cada vez más siglas:</p>
<p>LLM, RAG, MCP, KCP, A2A, Skills, Playbooks, Jev...</p>
<p>Es fácil pensar:</p>
<blockquote>
<p>¿Cuál reemplaza a cuál?</p>
</blockquote>
<p>Creo que es una pregunta equivocada.</p>
<p>Es mejor preguntar:</p>
<blockquote>
<p><strong>¿Qué problema resuelve cada pieza?</strong></p>
</blockquote>
<table>
<thead>
<tr>
<th>Pieza</th>
<th>En cristiano</th>
<th>En una clínica</th>
</tr>
</thead>
<tbody><tr>
<td>LLM</td>
<td>¿Cómo razono o genero una respuesta?</td>
<td>La médica piensa y explica</td>
</tr>
<tr>
<td>RAG</td>
<td>¿Qué documentos parecen relevantes?</td>
<td>Revisar el archivo</td>
</tr>
<tr>
<td>KCP</td>
<td>¿Qué conocimiento manda, está vigente y puedo utilizar?</td>
<td>El protocolo de este año, no el de 2024</td>
</tr>
<tr>
<td>MCP</td>
<td>¿A qué sistemas y herramientas puedo acceder?</td>
<td>Historia clínica, laboratorio, kardex</td>
</tr>
<tr>
<td>A2A</td>
<td>¿Se lo paso a otro agente?</td>
<td>Interconsulta a farmacia</td>
</tr>
<tr>
<td>Skills / Playbooks</td>
<td>¿Cómo se ejecuta este procedimiento?</td>
<td>La guía para tratar un caso específico</td>
</tr>
<tr>
<td>Jev / modelo de decisión</td>
<td>Dado este input permitido, ¿qué decisión estructurada corresponde?</td>
<td>¿Farmacia, calidad o revisión humana?</td>
</tr>
</tbody></table>
<p>Una forma todavía más sencilla:</p>
<pre><code class="language-plaintext">MCP       → ¿A qué puedo acceder?

KCP       → ¿Qué conocimiento/regla es válido?

Skills    → ¿Qué sé hacer?

Playbooks → ¿Cómo se ejecuta un procedimiento?

A2A       → ¿Con qué otro agente colaboro?

Jev       → ¿Qué decisión estructurada corresponde?

Audit     → ¿Qué ocurrió y puedo demostrarlo?
</code></pre>
<p>No son necesariamente competidores.</p>
<p>Son piezas diferentes de una arquitectura de agentes.</p>
<h2>2. El dibujo fácil — y por qué puede engañar</h2>
<p>Cuando alguien pide:</p>
<blockquote>
<p>"Dibújame el stack de Agentic AI"</p>
</blockquote>
<p>es tentador hacer esto:</p>
<pre><code class="language-plaintext">                    AGENT
                      │
          ┌───────────┼───────────┐
          │           │           │
         KCP         MCP         A2A
          │           │           │
          └───────────┼───────────┘
                      │
                     Jev
                      │
                    ACTION
</code></pre>
<p>Se ve bonito.</p>
<p>Pero tiene un problema:</p>
<p><strong>parece que Jev está debajo de KCP, MCP y A2A como si fuera otra capa del mismo tipo.</strong></p>
<p>No necesariamente.</p>
<p>Una arquitectura más útil conceptualmente sería:</p>
<pre><code class="language-plaintext">                         AGENT
                           │
             ┌─────────────┼─────────────┐
             │             │             │
            KCP           MCP           A2A
             │             │             │
        conocimiento      tools        agentes
        y gobierno        y datos      externos
             │
             ▼
      contexto autorizado
             │
             ▼
       MODELO DE DECISIÓN
        Jev / LLM / otro
             │
             ▼
       decisión estructurada
       choice + score + etc.
             │
             ▼
        POLICY / GATE
             │
        ┌────┴────┐
        ▼         ▼
      ACTION     HUMAN
        │
        ▼
       AUDIT
        │
        ▼
     EVIDENCE
</code></pre>
<p>La idea importante es:</p>
<blockquote>
<p><strong>El modelo puede proponer una decisión. La política determina qué se puede hacer con esa decisión.</strong></p>
</blockquote>
<h2>3. ¿Qué es cada uno, sin folleto?</h2>
<h2>MCP — ¿a qué puedo entrar?</h2>
<p>MCP es la capa de conexión con herramientas y recursos.</p>
<p>Por ejemplo:</p>
<pre><code class="language-plaintext">Agent
  │
  ├── MCP → PostgreSQL
  ├── MCP → GitHub
  ├── MCP → SAP
  ├── MCP → REST API
  └── MCP → filesystem
</code></pre>
<p>Pregunta:</p>
<blockquote>
<p><strong>¿Qué herramientas y recursos tengo disponibles?</strong></p>
</blockquote>
<p>Yo lo veo como el <strong>enchufe</strong>.</p>
<h2>KCP — ¿qué conocimiento manda?</h2>
<p>KCP entra en otro problema.</p>
<p>Supongamos que RAG encuentra:</p>
<pre><code class="language-plaintext">Política de crédito 2024
Política de crédito 2025
Política de crédito 2026
</code></pre>
<p>Encontrar documentos no significa saber cuál tiene autoridad.</p>
<p>KCP introduce una capa para declarar conocimiento y contexto gobernado:</p>
<pre><code class="language-plaintext">Documento
   │
   ├── versión
   ├── vigencia
   ├── alcance
   ├── audiencia
   ├── autoridad
   └── relación con otros documentos
</code></pre>
<p>Y el ecosistema ha ido más allá del documento:</p>
<pre><code class="language-plaintext">Knowledge
    ↓
Skills
    ↓
Playbooks
</code></pre>
<p>Por eso no lo describiría simplemente como "un inventario de documentos".</p>
<p>Es más preciso decir:</p>
<blockquote>
<p><strong>KCP es una capa de conocimiento y gobernanza para declarar qué conocimiento, capacidades y procedimientos están disponibles y bajo qué condiciones.</strong></p>
</blockquote>
<h2>A2A — ¿se lo paso a otro agente?</h2>
<p>A2A responde otra pregunta:</p>
<blockquote>
<p><strong>¿Cómo colaboro con otro agente?</strong></p>
</blockquote>
<p>Por ejemplo:</p>
<pre><code class="language-plaintext">Customer Agent
      │
      ├──→ Credit Agent
      │
      ├──→ Fraud Agent
      │
      └──→ Shipping Agent
</code></pre>
<p>MCP:</p>
<pre><code class="language-plaintext">Agent ↔ Tool
</code></pre>
<p>A2A:</p>
<pre><code class="language-plaintext">Agent ↔ Agent
</code></pre>
<p>Son complementarios.</p>
<h2>Skills y Playbooks — ¿cómo hago el trabajo?</h2>
<p>Una cosa es saber que puedes acceder a una herramienta.</p>
<p>Otra es saber cómo utilizarla correctamente.</p>
<p>Por ejemplo:</p>
<p>Skill: "Analizar una solicitud de crédito"</p>
<p>Playbook:</p>
<ol>
<li><p>Obtener datos</p>
</li>
<li><p>Validar identidad</p>
</li>
<li><p>Consultar política vigente</p>
</li>
<li><p>Evaluar riesgo</p>
</li>
<li><p>Solicitar revisión si corresponde</p>
</li>
<li><p>Registrar evidencia</p>
</li>
</ol>
<p>Aquí empieza a aparecer una arquitectura mucho más interesante que simplemente:</p>
<p>"Tengo un chatbot conectado a una API."</p>
<h2>Jev — ¿qué decisión estructurada corresponde?</h2>
<p>Aquí está la diferencia fundamental.</p>
<p>Un LLM tradicional puede responder:</p>
<blockquote>
<p>"Creo que este caso debería ser revisado por el área de fraude porque..."</p>
</blockquote>
<p>Un modelo de decisión puede producir algo más cercano a:</p>
<pre><code class="language-plaintext">{
  "decision": "fraud-review",
  "confidence": 0.82
}
</code></pre>
<p>O:</p>
<pre><code class="language-plaintext">{
  "category": "A",
  "score": 82,
  "probability": 0.91
}
</code></pre>
<p>La idea de Jev es precisamente llevar el modelo hacia <strong>decisiones tipadas/probabilísticas en lugar de generación abierta</strong>.</p>
<p>Eso puede ser muy útil cuando el espacio de respuestas está controlado.</p>
<p>Pero aquí aparece una distinción fundamental.</p>
<h2>4. "0% de alucinaciones" no significa "0% de errores"</h2>
<p>Este punto merece mucha atención.</p>
<p>Una salida estructurada puede garantizar que el modelo solamente devuelva:</p>
<pre><code class="language-plaintext">APPROVE
REFUSE
ESCALATE
</code></pre>
<p>Eso evita que el modelo invente una cuarta opción:</p>
<pre><code class="language-plaintext">MAYBE-PERHAPS-APPROVE
</code></pre>
<p>Pero no significa que:</p>
<pre><code class="language-plaintext">APPROVE
</code></pre>
<p>sea necesariamente la decisión correcta.</p>
<p>El propio análisis de Thor sobre Jev señala precisamente esta diferencia: la afirmación de "0% hallucination" se refiere a la garantía del esquema de salida, no a una garantía empírica de corrección.</p>
<p>Dicho de otra manera:</p>
<pre><code class="language-plaintext">Schema correctness
        ≠
Decision correctness
</code></pre>
<p>Si las únicas opciones son:</p>
<pre><code class="language-plaintext">APPROVE
REFUSE
</code></pre>
<p>el modelo siempre devolverá una de ellas.</p>
<p>Pero todavía puede equivocarse.</p>
<h2>5. Y aquí aparece una palabra importante: calibración</h2>
<p>Supongamos que el modelo responde:</p>
<pre><code class="language-plaintext">decision = APPROVE
confidence = 0.82
</code></pre>
<p>La pregunta importante es:</p>
<blockquote>
<p><strong>¿Ese 0.82 significa realmente algo?</strong></p>
</blockquote>
<p>¿Significa que acertará aproximadamente el 82% de las veces?</p>
<p>¿O simplemente es un número que el modelo produce con mucha seguridad?</p>
<p>Para responderlo necesitamos datos.</p>
<p>Por ejemplo:</p>
<pre><code class="language-plaintext">Confidence       Resultado real

0.50 – 0.59      58% correctas
0.60 – 0.69      67% correctas
0.70 – 0.79      75% correctas
0.80 – 0.89      84% correctas
0.90 – 0.99      92% correctas
</code></pre>
<p>Entonces podríamos empezar a hablar de una confianza calibrada.</p>
<p>Pero si todas nuestras decisiones son:</p>
<pre><code class="language-plaintext">0.85
0.87
0.91
0.89
0.90
0.88
</code></pre>
<p>y nunca tenemos suficientes casos con otros niveles de confianza, <strong>no podemos saber realmente si el número está calibrado</strong>.</p>
<p>Eso es exactamente una de las cosas interesantes que descubrió Thor al auditar su propio sistema.</p>
<p>Su gateway llevaba meses produciendo decisiones tipadas, <code>confidence</code> y referencias a reglas. Pero cuando intentaron comprobar si el <code>confidence</code> realmente predecía la corrección, descubrieron que sus propios datos todavía no permitían responderlo.</p>
<p>Y esa es una lección que me parece mucho más importante que cualquier benchmark:</p>
<blockquote>
<p><strong>Un número de confianza necesita evidencia.</strong></p>
</blockquote>
<h2>6. Un <code>0.82</code> no es una firma</h2>
<p>Esta frase merece su propia sección.</p>
<p>Podemos tener:</p>
<pre><code class="language-plaintext">decision = APPROVE
confidence = 0.82
</code></pre>
<p>Incluso podemos firmarlo criptográficamente.</p>
<p>Eso nos permite demostrar:</p>
<blockquote>
<p>"El sistema produjo esta decisión con este valor."</p>
</blockquote>
<p>Pero no demuestra:</p>
<blockquote>
<p>"La decisión era correcta."</p>
</blockquote>
<p>Son cosas diferentes.</p>
<pre><code class="language-plaintext">Firma
  │
  ▼
Prueba de lo que ocurrió

Calibración
  │
  ▼
Evidencia sobre qué tan confiable es el número

Política
  │
  ▼
Qué podemos hacer con esa decisión
</code></pre>
<p>Por eso una arquitectura de agentes empresarial necesita algo más que modelos.</p>
<p>Necesita <strong>gobernanza y evidencia</strong>.</p>
<h2>7. El caso de Ana López</h2>
<p>Imaginemos que tenemos una clínica.</p>
<p>Ana López está hospitalizada y llega este texto:</p>
<blockquote>
<p>"Paciente presenta potasio elevado y está tomando medicación X."</p>
</blockquote>
<p>Nuestro sistema podría tener:</p>
<h3>RAG</h3>
<p>Encuentra:</p>
<pre><code class="language-plaintext">Protocolo 2024
Protocolo 2025
Protocolo 2026
</code></pre>
<h3>KCP</h3>
<p>Determina:</p>
<pre><code class="language-plaintext">Protocolo 2026
vigente
aplicable a este tipo de caso
</code></pre>
<h3>MCP</h3>
<p>Permite consultar:</p>
<pre><code class="language-plaintext">Historia clínica
Laboratorio
Medicamentos
</code></pre>
<h3>Skill / Playbook</h3>
<p>Define:</p>
<pre><code class="language-plaintext">Analizar hiperpotasemia
</code></pre>
<h3>A2A</h3>
<p>Puede delegar:</p>
<pre><code class="language-plaintext">Medical Agent
      │
      └──→ Pharmacy Agent
</code></pre>
<h3>Modelo de decisión</h3>
<p>Recibe el contexto autorizado:</p>
<pre><code class="language-plaintext">decision = "pharmacy-review"
confidence = 0.82
</code></pre>
<p>Pero todavía falta una pregunta:</p>
<blockquote>
<p><strong>¿Qué hacemos con ese 0.82?</strong></p>
</blockquote>
<p>La política podría decir:</p>
<pre><code class="language-plaintext">if confidence &lt; 0.75
    → human review

if medication == high-risk
    → human review

if policy requires physician
    → human review
</code></pre>
<p>Entonces:</p>
<pre><code class="language-plaintext">            KCP
             │
             ▼
     contexto autorizado
             │
             ▼
       modelo de decisión
             │
             ▼
      pharmacy-review
          0.82
             │
             ▼
          POLICY
             │
             ▼
       HUMAN REVIEW
             │
             ▼
           AUDIT
</code></pre>
<p>Ahora sí tenemos una arquitectura defendible.</p>
<h2>8. Lo más interesante: la auditoría también puede equivocarse</h2>
<p>Y aquí el artículo de Thor tiene una segunda lección todavía más interesante.</p>
<p>Al auditar sus decisiones, inicialmente encontraron:</p>
<pre><code class="language-plaintext">21 decisiones escaladas
21 aparentemente pendientes
</code></pre>
<p>Parecía un problema importante.</p>
<p>Pero el script de auditoría estaba utilizando mal un identificador de correlación.</p>
<p>Al corregir la relación entre eventos, el resultado cambió.</p>
<p>Y posteriormente encontraron otro problema: algunas de las decisiones que parecían pendientes pertenecían a ejecuciones que ya habían terminado o sido abortadas.</p>
<p>La conclusión es brutalmente sencilla:</p>
<blockquote>
<p><strong>Un sistema de auditoría también necesita ser auditado.</strong></p>
</blockquote>
<p>Podemos tener:</p>
<pre><code class="language-plaintext">Agent
  ↓
Decision
  ↓
Audit
</code></pre>
<p>y aun así equivocarnos.</p>
<p>Por eso no basta con:</p>
<blockquote>
<p>"Tengo logs."</p>
</blockquote>
<p>Hay que poder responder:</p>
<ul>
<li><p>¿Qué versión de la política estaba vigente?</p>
</li>
<li><p>¿Qué conocimiento se utilizó?</p>
</li>
<li><p>¿Qué modelo produjo la decisión?</p>
</li>
<li><p>¿Qué input recibió?</p>
</li>
<li><p>¿Qué decisión propuso?</p>
</li>
<li><p>¿Qué confidence produjo?</p>
</li>
<li><p>¿Qué regla la justificó?</p>
</li>
<li><p>¿Quién autorizó la acción?</p>
</li>
<li><p>¿Qué ocurrió después?</p>
</li>
<li><p>¿Podemos reconstruir el proceso?</p>
</li>
</ul>
<p>Eso es <strong>evidence</strong>.</p>
<h2>9. Entonces, ¿Jev reemplaza a KCP?</h2>
<p>No.</p>
<p>Pero tampoco diría simplemente:</p>
<blockquote>
<p>"KCP y Jev son complementarios."</p>
</blockquote>
<p>Eso es demasiado superficial.</p>
<p>La relación más interesante es:</p>
<pre><code class="language-plaintext">             KNOWLEDGE
                 │
                KCP
                 │
                 ▼
       CONTEXTO AUTORIZADO
                 │
                 ▼
          DECISION MODEL
        Jev / LLM / otro
                 │
                 ▼
       DECISIÓN PROPUESTA
                 │
                 ▼
          POLICY / GATE
                 │
          ┌──────┴──────┐
          ▼             ▼
       ACTION         HUMAN
          │
          ▼
         AUDIT
          │
          ▼
       EVIDENCE
</code></pre>
<p>Por eso el título sigue siendo:</p>
<h1><strong>Jev vs KCP: no es un versus</strong></h1>
<p>Pero ahora agregaría:</p>
<blockquote>
<p><strong>En realidad, tampoco es solamente Jev + KCP. Hay una tercera dimensión: gobernar y demostrar qué ocurrió.</strong></p>
</blockquote>
<h1>10. Si tu equipo programa — Java u otra cosa</h1>
<p>Todo esto no depende de Java.</p>
<p>Pero para un equipo Java podría verse perfectamente así:</p>
<pre><code class="language-plaintext">Spring AI / LangChain4j / Quarkus
              │
              ▼
          AI Agent
              │
       ┌──────┼──────┐
       │      │      │
      KCP    MCP    A2A
       │      │      │
       │      │      └── Agent B
       │      │
       │      └──────── APIs / DB / Tools
       │
       └────────────── Knowledge / Policies
              │
              ▼
        Decision Model
              │
              ▼
      Structured Output
              │
              ▼
          Policy Gate
              │
          ┌───┴───┐
          ▼       ▼
        Action   Human
          │
          ▼
      Audit Trail
</code></pre>
<p>Y aquí está la parte que más me interesa como arquitecto:</p>
<p><strong>no estamos construyendo simplemente un chatbot.</strong></p>
<p>Estamos construyendo un sistema donde:</p>
<pre><code class="language-plaintext">Knowledge
    +
Tools
    +
Agents
    +
Decision
    +
Governance
    +
Evidence
</code></pre>
<p>forman una unidad.</p>
<h1>11. Cómo lo contaría en diez minutos</h1>
<p>Si tuviera que explicar todo esto rápidamente, usaría solamente estas preguntas:</p>
<h3>1. ¿Qué puedo usar?</h3>
<p><strong>MCP</strong></p>
<pre><code class="language-plaintext">Agent → Tools / Data
</code></pre>
<h3>2. ¿Qué conocimiento es válido?</h3>
<p><strong>KCP</strong></p>
<pre><code class="language-plaintext">Agent → Governed Knowledge
</code></pre>
<h3>3. ¿Cómo hago el trabajo?</h3>
<p><strong>Skills / Playbooks</strong></p>
<pre><code class="language-plaintext">Agent → Procedure
</code></pre>
<h3>4. ¿Con qué otro agente colaboro?</h3>
<p><strong>A2A</strong></p>
<pre><code class="language-plaintext">Agent ↔ Agent
</code></pre>
<h3>5. ¿Qué decisión corresponde?</h3>
<p><strong>Jev / modelo de decisión</strong></p>
<pre><code class="language-plaintext">Input → Decision + Score
</code></pre>
<h3>6. ¿Qué puedo hacer con esa decisión?</h3>
<p><strong>Policy / Governance</strong></p>
<pre><code class="language-plaintext">Decision → Action / Human
</code></pre>
<h3>7. ¿Cómo demuestro lo que pasó?</h3>
<p><strong>Audit / Evidence</strong></p>
<pre><code class="language-plaintext">Action → Trace → Evidence
</code></pre>
<p>Y ahí aparece una arquitectura mucho más completa:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/b223755a-eead-4c07-bd5b-ac2f8ff819c7.png" alt="" style="display:block;margin:0 auto" />

<h1>Cierre</h1>
<p>Mi conclusión después de mirar Jev y KCP es que la pregunta:</p>
<blockquote>
<p><strong>"¿Jev o KCP?"</strong></p>
</blockquote>
<p>no es la pregunta que deberíamos hacernos.</p>
<p>La pregunta interesante es:</p>
<blockquote>
<p><strong>"¿Qué necesita un agente para conocer, decidir, actuar y poder defender después lo que hizo?"</strong></p>
</blockquote>
<p>Ahí cada pieza tiene un papel diferente.</p>
<p><strong>MCP</strong> conecta al agente con herramientas y datos.</p>
<p><strong>KCP</strong> ayuda a gobernar el conocimiento, las capacidades y los procedimientos que puede utilizar.</p>
<p><strong>Skills y Playbooks</strong> describen cómo realizar determinados trabajos.</p>
<p><strong>A2A</strong> permite colaborar con otros agentes.</p>
<p><strong>Jev</strong>, o cualquier modelo de decisión estructurada, puede ayudar a convertir un input en una decisión tipada, un score o una probabilidad.</p>
<p>Pero hay una advertencia importante:</p>
<blockquote>
<p><strong>Un</strong> <code>confidence: 0.82</code> <strong>no demuestra que la decisión sea correcta.</strong></p>
</blockquote>
<p>Para eso necesitamos datos, calibración y evidencia.</p>
<p>Y tampoco basta con tener un audit log.</p>
<p>El propio proceso de auditoría puede equivocarse.</p>
<p>Por eso, para mí, la arquitectura de agentes empresariales empieza a verse así:</p>
<pre><code class="language-plaintext">KNOWLEDGE
    ↓
GOVERNANCE
    ↓
DECISION
    ↓
ACTION
    ↓
EVIDENCE
</code></pre>
<p>O, en una frase:</p>
<blockquote>
<p><strong>KCP ayuda a establecer qué vale y qué está permitido. Un modelo como Jev puede proponer qué decisión corresponde. La política determina qué puede ocurrir después. Y la evidencia permite demostrar qué ocurrió realmente.</strong></p>
</blockquote>
<p><strong>No es un versus. Es un sistema.</strong></p>
<h3><strong>Referencias</strong></h3>
<ul>
<li><p>Thor Henning Hetland — <a href="https://wiki.totto.org/blog/2026/09/18/we-already-run-jev-we-just-never-checked/"><em><strong>We Already Run Jev. We Just Never Checked</strong></em></a><em>.</em></p>
</li>
<li><p>JoeDayz — <a href="https://blog.joedayz.pe/jev-vs-kcp-no-es-un-versus"><em><strong>Jev vs KCP: no es un versus</strong></em></a></p>
</li>
<li><p>KCP — <a href="https://github.com/Cantara/knowledge-context-protocol"><strong>Knowledge Context Protocol</strong></a></p>
</li>
<li><p>Jev AI — <a href="https://jevai.net/es/"><strong>TypeSafe AI</strong></a></p>
</li>
</ul>
<p>Enjoy!</p>
<p>Joe</p>
]]></content:encoded></item><item><title><![CDATA[De agentes que generan respuestas a organizaciones que aprenden]]></title><description><![CDATA[Durante los últimos años hemos visto una evolución bastante rápida de la inteligencia artificial. Primero aprendimos a conversar con modelos. Después…]]></description><link>https://joedayz.hashnode.dev/de-agentes-que-generan-respuestas-a-organizaciones-que-aprenden</link><guid isPermaLink="true">https://joedayz.hashnode.dev/de-agentes-que-generan-respuestas-a-organizaciones-que-aprenden</guid><category><![CDATA[joedayz]]></category><category><![CDATA[genai]]></category><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Sun, 20 Sep 2026 05:39:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/fa952766-43b9-4319-bfaa-6319c2192788.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Durante los últimos años hemos visto una evolución bastante rápida de la inteligencia artificial.</p>
<p>Primero aprendimos a conversar con modelos.</p>
<p>Después empezamos a utilizarlos para escribir código, analizar documentos, generar contenido y consultar información.</p>
<p>Ahora estamos entrando en una etapa diferente: <strong>los agentes</strong>.</p>
<p>Un agente no solamente responde. Puede consultar sistemas, utilizar herramientas, ejecutar procesos, modificar información y coordinarse con otros agentes.</p>
<p>Y aquí aparece una pregunta que considero mucho más importante que simplemente preguntar qué tan inteligente es nuestro modelo:</p>
<blockquote>
<p><strong>¿Cómo hacemos para que un agente pueda actuar con autonomía sin perder el contexto, la trazabilidad, la seguridad y el control humano?</strong></p>
</blockquote>
<p>Porque poner un LLM detrás de una API y darle permisos para ejecutar acciones no convierte automáticamente nuestro sistema en una arquitectura agentic.</p>
<p>De hecho, probablemente sea una receta bastante rápida para tener problemas.</p>
<p>Lo interesante es que, cuando empezamos a pensar seriamente en agentes, aparecen una serie de capacidades que antes podían parecer secundarias: memoria, conocimiento, herramientas, autorización, auditoría, verificación y aprendizaje.</p>
<p>Y todas terminan conectándose.</p>
<h1>El problema no es que la IA produzca poco</h1>
<p>Durante mucho tiempo el objetivo fue conseguir que la IA produjera más.</p>
<p>Más código.</p>
<p>Más documentos.</p>
<p>Más análisis.</p>
<p>Más respuestas.</p>
<p>Pero cuando tenemos varios agentes trabajando en paralelo aparece un problema diferente.</p>
<p>Supongamos que tenemos:</p>
<pre><code class="language-plaintext">Agente A → analiza incidencias
Agente B → revisa código
Agente C → actualiza documentación
Agente D → ejecuta pruebas
Agente E → prepara cambios
</code></pre>
<p>La capacidad de producción puede crecer rápidamente.</p>
<p>Pero el humano sigue siendo uno.</p>
<p>Y ese humano tiene que:</p>
<ul>
<li><p>revisar resultados;</p>
</li>
<li><p>tomar decisiones;</p>
</li>
<li><p>validar información;</p>
</li>
<li><p>aprobar acciones;</p>
</li>
<li><p>investigar errores.</p>
</li>
</ul>
<p>Entonces el cuello de botella cambia.</p>
<p>Ya no es necesariamente:</p>
<blockquote>
<p>"¿Cuánto puede producir la IA?"</p>
</blockquote>
<p>Sino:</p>
<blockquote>
<p><strong>"¿Cuánto trabajo puede absorber y verificar una persona?"</strong></p>
</blockquote>
<p>Esto cambia completamente la arquitectura que necesitamos.</p>
<h1>1. Un agente no puede empezar desde cero</h1>
<p>Imaginemos que tenemos un agente excelente.</p>
<p>Tiene un buen modelo, buenas herramientas y acceso a nuestros sistemas.</p>
<p>Pero cada vez que iniciamos una sesión no sabe:</p>
<ul>
<li><p>qué ocurrió ayer;</p>
</li>
<li><p>qué decisiones tomamos;</p>
</li>
<li><p>qué aprendimos;</p>
</li>
<li><p>qué solución fue descartada;</p>
</li>
<li><p>qué procedimiento funciona actualmente;</p>
</li>
<li><p>qué tiene permitido hacer.</p>
</li>
</ul>
<p>Tenemos un agente muy capaz que todos los días parece ser su primer día de trabajo.</p>
<p>Por eso necesitamos diferentes tipos de conocimiento.</p>
<p>Una forma sencilla de verlo es:</p>
<pre><code class="language-plaintext">Episódico
¿Qué ocurrió?

      ↓

Conocimiento
¿Qué creemos que es cierto?

      ↓

Skills
¿Cuál es el método validado?

      ↓

Playbooks
¿Cómo combinamos esos métodos?

      ↓

Gobernanza
¿Qué puede hacer el agente?
</code></pre>
<p>Esto cambia el ciclo de trabajo.</p>
<p>Ya no sería simplemente:</p>
<pre><code class="language-plaintext">pregunta → respuesta
</code></pre>
<p>sino:</p>
<pre><code class="language-plaintext">orientar
   ↓
recuperar contexto
   ↓
ejecutar
   ↓
verificar
   ↓
decidir
   ↓
aprender
   ↺
</code></pre>
<p>La siguiente ejecución comienza con lo aprendido en la anterior.</p>
<p>Ahí empieza a aparecer algo mucho más interesante que un chatbot:</p>
<p><strong>memoria institucional.</strong></p>
<h1>2. Una respuesta no es conocimiento</h1>
<p>Este punto parece obvio, pero se vuelve fundamental cuando dejamos que los agentes actúen.</p>
<p>Que un agente diga:</p>
<blockquote>
<p>"El problema está en el servicio de pagos."</p>
</blockquote>
<p>no significa que sea cierto.</p>
<p>Tenemos que poder distinguir:</p>
<pre><code class="language-plaintext">Afirmación
    ↓
Fuente
    ↓
Evidencia
    ↓
Verificación
    ↓
Conocimiento confiable
</code></pre>
<p>Esto nos lleva al concepto de <strong>provenance</strong> o trazabilidad.</p>
<p>Cuando un agente toma una decisión importante deberíamos poder responder:</p>
<ul>
<li><p>¿qué información utilizó?</p>
</li>
<li><p>¿de dónde salió?</p>
</li>
<li><p>¿qué regla aplicó?</p>
</li>
<li><p>¿qué versión del conocimiento utilizó?</p>
</li>
<li><p>¿quién autorizó la acción?</p>
</li>
<li><p>¿qué ocurrió finalmente?</p>
</li>
</ul>
<p>Por ejemplo:</p>
<pre><code class="language-plaintext">Agente:        billing-agent
Acción:        actualizar factura
Fuente:        ERP
Regla:         billing-update-v3
Autorización:  policy-17
Resultado:     success
Evidencia:     ...
</code></pre>
<p>Esto convierte una acción del agente en algo que podemos reconstruir posteriormente.</p>
<p>Pero hay una distinción importante:</p>
<blockquote>
<p><strong>Tener trazabilidad no significa tener razón.</strong></p>
</blockquote>
<p>Una firma puede demostrar que una acción ocurrió y quién la produjo.</p>
<p>No demuestra que la acción fuera correcta.</p>
<p>Por eso necesitamos combinar:</p>
<pre><code class="language-plaintext">Provenance
+
Autorización
+
Evidencia
+
Verificación
</code></pre>
<h1>3. No hagamos que el agente descubra lo que el sistema ya sabe</h1>
<p>Aquí aparece otro problema.</p>
<p>Imaginemos un agente interactuando con una aplicación web:</p>
<pre><code class="language-plaintext">Agente
  ↓
abre página
  ↓
busca botón
  ↓
interpreta texto
  ↓
hace clic
  ↓
comprueba resultado
</code></pre>
<p>El agente está intentando descubrir cómo funciona nuestro sistema a través de su interfaz.</p>
<p>¿Por qué no declarar directamente las capacidades?</p>
<p>Por ejemplo:</p>
<pre><code class="language-plaintext">getCustomer(customerId)

createInvoice(customerId, items)

cancelInvoice(invoiceId)

approveRefund(refundId)
</code></pre>
<p>Ahora el agente sabe exactamente qué puede hacer y qué parámetros necesita.</p>
<p>La arquitectura cambia:</p>
<pre><code class="language-plaintext">ANTES

Agente → UI → DOM → interpretación → acción


DESPUÉS

Agente → capacidad declarada → contrato → acción
</code></pre>
<p>Esto no solamente facilita el trabajo del agente.</p>
<p>También facilita:</p>
<ul>
<li><p>testing;</p>
</li>
<li><p>autorización;</p>
</li>
<li><p>auditoría;</p>
</li>
<li><p>documentación;</p>
</li>
<li><p>observabilidad;</p>
</li>
<li><p>reutilización.</p>
</li>
</ul>
<p>Y aparece una idea interesante:</p>
<blockquote>
<p><strong>La interfaz deja de ser necesariamente la fuente principal de información sobre lo que un sistema puede hacer.</strong></p>
</blockquote>
<p>Las capacidades pueden declararse explícitamente.</p>
<h1>4. El agente necesita brazos, no solamente voz</h1>
<p>Un chatbot tiene voz.</p>
<p>Un agente necesita brazos.</p>
<p>Es decir, necesita poder actuar:</p>
<pre><code class="language-plaintext">Leer información
       ↓
Usar API
       ↓
Modificar información
       ↓
Ejecutar procesos
       ↓
Interactuar con otros sistemas
</code></pre>
<p>Pero aquí aparece un problema:</p>
<p><strong>¿Qué acciones puede ejecutar?</strong></p>
<p>No deberíamos responder:</p>
<blockquote>
<p>"Las que permita su API key."</p>
</blockquote>
<p>Eso es demasiado grueso.</p>
<p>La pregunta debería ser mucho más específica:</p>
<blockquote>
<p><strong>¿Este agente puede realizar esta acción, sobre este recurso, en este contexto y en este momento?</strong></p>
</blockquote>
<p>Por ejemplo:</p>
<pre><code class="language-plaintext">crear PR                  → automático
ejecutar tests            → automático
modificar documentación   → automático

desplegar producción      → supervisión

eliminar base de datos    → aprobación explícita
transferir dinero         → aprobación explícita
</code></pre>
<p>La autonomía debería estar asociada a la <strong>acción</strong>, no solamente al agente.</p>
<h1>5. La autonomía es un dial</h1>
<p>Uno de los errores más comunes es pensar:</p>
<pre><code class="language-plaintext">NO AUTÓNOMO ←→ AUTÓNOMO
</code></pre>
<p>En realidad necesitamos algo mucho más gradual:</p>
<pre><code class="language-plaintext">Manual
   ↓
Automático con aprobación
   ↓
Automático con verificación
   ↓
Agente supervisado
   ↓
Agente autónomo
</code></pre>
<p>Y la posición depende de factores como:</p>
<ul>
<li><p>riesgo;</p>
</li>
<li><p>reversibilidad;</p>
</li>
<li><p>alcance;</p>
</li>
<li><p>historial;</p>
</li>
<li><p>calidad de la evidencia;</p>
</li>
<li><p>autorización.</p>
</li>
</ul>
<p>Un agente puede tener autonomía completa para limpiar ejecuciones de pruebas y necesitar aprobación humana para modificar producción.</p>
<p>No hay contradicción.</p>
<p><strong>Son dos acciones diferentes.</strong></p>
<h1>6. Human-in-the-loop no significa aprobar todo</h1>
<p>Aquí creo que aparece una de las ideas más importantes.</p>
<p>Durante mucho tiempo hemos pensado en <em>Human-in-the-loop</em> como:</p>
<pre><code class="language-plaintext">Agente
  ↓
Humano
  ↓
Approve
</code></pre>
<p>Pero si hacemos esto para cada acción:</p>
<pre><code class="language-plaintext">acción 1 → aprobar
acción 2 → aprobar
acción 3 → aprobar
acción 4 → aprobar
...
</code></pre>
<p>tenemos un problema.</p>
<p>El humano termina haciendo clic en "Approve" sin leer.</p>
<p>La seguridad se convierte en una ilusión.</p>
<p>Una arquitectura más interesante es:</p>
<pre><code class="language-plaintext">                 ACCIÓN
                   ↓
          ¿Necesita juicio humano?
             ↙          ↘
           NO            SÍ
           ↓             ↓
       automático     humano correcto
                         ↓
                      decisión
</code></pre>
<p>Por ejemplo:</p>
<pre><code class="language-plaintext">100 acciones
     ↓
95 → automáticas
 5 → revisión humana
</code></pre>
<p>El objetivo no es sacar al humano del sistema.</p>
<p>Es <strong>sacar del camino del humano todo lo que no necesita su juicio</strong>.</p>
<h1>7. Permiso no significa relevancia</h1>
<p>Esto también cambia la forma en que pensamos las notificaciones.</p>
<p>Una persona puede tener permiso para acceder a un proyecto.</p>
<p>Pero eso no significa que tenga que recibir todas las notificaciones de ese proyecto.</p>
<p>Tenemos dos conceptos diferentes:</p>
<pre><code class="language-plaintext">PERMISSION
¿Puede verlo?

RELEVANCE
¿Necesita recibirlo?
</code></pre>
<p>Podemos agregar una tercera dimensión:</p>
<pre><code class="language-plaintext">URGENCY
¿Necesita saberlo ahora?
</code></pre>
<p>Entonces:</p>
<pre><code class="language-plaintext">Permission
     +
Relevance
     +
Urgency
     ↓
Delivery
</code></pre>
<p>Esto permite construir sistemas donde la mayoría de las cosas llegan como un resumen:</p>
<pre><code class="language-plaintext">Digest

"Hay 27 elementos para revisar."
</code></pre>
<p>Y solamente las situaciones realmente importantes interrumpen:</p>
<pre><code class="language-plaintext">Alert

"Esta acción requiere tu decisión."
</code></pre>
<p>Esto es importante porque la atención humana es un recurso limitado.</p>
<p>Si todo genera una alerta, ninguna alerta termina siendo realmente importante.</p>
<h1>8. La confianza no se declara, se construye</h1>
<p>Si queremos aumentar la autonomía de un agente necesitamos saber cuándo podemos confiar en él.</p>
<p>No basta con decir:</p>
<blockquote>
<p>"Este modelo es muy bueno."</p>
</blockquote>
<p>Necesitamos observar su comportamiento.</p>
<pre><code class="language-plaintext">Historial
   ↓
Resultados
   ↓
Verificación
   ↓
Desviaciones
   ↓
Confianza
   ↓
Autonomía permitida
</code></pre>
<p>Y esa confianza tampoco debería ser permanente.</p>
<p>Si cambiamos:</p>
<ul>
<li><p>el modelo;</p>
</li>
<li><p>las herramientas;</p>
</li>
<li><p>los datos;</p>
</li>
<li><p>las reglas;</p>
</li>
<li><p>el contexto;</p>
</li>
<li><p>el alcance;</p>
</li>
</ul>
<p>tenemos que preguntarnos nuevamente:</p>
<blockquote>
<p><strong>¿La autorización y el nivel de autonomía siguen siendo válidos?</strong></p>
</blockquote>
<p>Un agente confiable para una tarea no necesariamente es confiable para otra.</p>
<h1>9. Pero aparece una pregunta incómoda: ¿quién verifica al verificador?</h1>
<p>Podemos construir:</p>
<pre><code class="language-plaintext">Agente
  ↓
Decisión
  ↓
Evidencia
  ↓
Auditor
  ↓
Resultado
</code></pre>
<p>Y sentirnos bastante tranquilos.</p>
<p>Hasta que descubrimos que el auditor tiene un bug.</p>
<p>Esto es importante porque introduce un nivel adicional:</p>
<blockquote>
<p><strong>Nuestra infraestructura de verificación también necesita ser verificada.</strong></p>
</blockquote>
<p>Podemos tener todos los logs del mundo y aun así interpretarlos mal.</p>
<p>Por ejemplo:</p>
<pre><code class="language-plaintext">Evento A
     ↓
Evento B
     ↓
Auditor
     ↓
"No están relacionados"
</code></pre>
<p>cuando en realidad sí pertenecen a la misma ejecución y simplemente estamos utilizando una clave de correlación incorrecta.</p>
<p>La lección es poderosa:</p>
<blockquote>
<p><strong>Los datos pueden ser correctos y nuestra interpretación de esos datos puede ser incorrecta.</strong></p>
</blockquote>
<h1>10. 1.500 tests pasando tampoco significa que todo esté bien</h1>
<p>Este problema también aparece en testing.</p>
<p>Podemos tener cientos o miles de pruebas pasando y descubrir un error en producción.</p>
<p>¿Por qué?</p>
<p>Porque podemos estar probando una representación simplificada del sistema real.</p>
<p>Por ejemplo:</p>
<pre><code class="language-plaintext">Test
 ↓
Mock
 ↓
OK
</code></pre>
<p>mientras que:</p>
<pre><code class="language-plaintext">Producción
 ↓
Restricción real
 ↓
FAIL
</code></pre>
<p>La cantidad de tests no es suficiente.</p>
<p>La pregunta importante es:</p>
<blockquote>
<p><strong>¿Qué propiedad del sistema estoy demostrando con este test?</strong></p>
</blockquote>
<p>Esto es especialmente relevante para gobernanza.</p>
<p>No basta con probar:</p>
<pre><code class="language-plaintext">"El botón de aprobación funciona."
</code></pre>
<p>Tenemos que probar:</p>
<pre><code class="language-plaintext">"Sin la aprobación requerida,
la acción realmente no puede ejecutarse."
</code></pre>
<p>Eso es mucho más cercano a una garantía real.</p>
<h1>11. Las políticas deben ser ejecutables</h1>
<p>Supongamos que nuestra documentación dice:</p>
<blockquote>
<p>"Los cambios en producción requieren aprobación."</p>
</blockquote>
<p>Perfecto.</p>
<p>Pero nuestro pipeline permite:</p>
<pre><code class="language-plaintext">git push
   ↓
deploy
</code></pre>
<p>sin comprobar ninguna aprobación.</p>
<p>Entonces tenemos una política documentada, pero no una política efectiva.</p>
<p>Una política realmente importante debería poder convertirse en una regla ejecutable:</p>
<pre><code class="language-plaintext">Cambio
  ↓
Pipeline
  ↓
¿Cumple política?
   ↙      ↘
 Sí       No
 ↓         ↓
Deploy   BLOCK
</code></pre>
<p>La diferencia es enorme.</p>
<p>Una política escrita expresa una intención.</p>
<p>Una política ejecutada por el sistema controla el comportamiento.</p>
<p>Y cuanto más autónomos sean nuestros agentes, más importante será esta distinción.</p>
<h1>12. También tenemos que guardar nuestros errores</h1>
<p>Normalmente almacenamos el conocimiento actual:</p>
<pre><code class="language-plaintext">"Esta es la forma correcta de hacerlo."
</code></pre>
<p>Pero también sería útil conservar:</p>
<pre><code class="language-plaintext">"Esta era nuestra hipótesis anterior."
"Esto fue lo que observamos."
"Esto la contradijo."
"Por eso cambiamos."
</code></pre>
<p>Por ejemplo:</p>
<pre><code class="language-plaintext">Hipótesis
   ↓
Evidencia
   ↓
Decisión
   ↓
Falsificación
   ↓
Nuevo conocimiento
</code></pre>
<p>Esto es especialmente importante para los agentes.</p>
<p>Si descubrimos que una determinada estrategia falla bajo ciertas condiciones, no queremos que el siguiente agente vuelva a descubrirlo desde cero.</p>
<p>Queremos que pueda recuperar:</p>
<blockquote>
<p>"Esta estrategia se utilizó anteriormente y falló cuando X estaba presente."</p>
</blockquote>
<p>Los errores dejan de ser simplemente errores.</p>
<p>Se convierten en <strong>memoria institucional</strong>.</p>
<h1>13. El objetivo no es hacer más. Es aprender más rápido.</h1>
<p>Aquí creo que está el verdadero cambio de paradigma.</p>
<p>La primera generación de sistemas de IA buscaba:</p>
<pre><code class="language-plaintext">Pregunta
   ↓
Respuesta
</code></pre>
<p>Los sistemas agentic buscan:</p>
<pre><code class="language-plaintext">Objetivo
   ↓
Plan
   ↓
Herramientas
   ↓
Acciones
   ↓
Resultados
</code></pre>
<p>Pero podemos ir un paso más allá:</p>
<pre><code class="language-plaintext">Trabajo
   ↓
Agente
   ↓
Resultado
   ↓
Verificación
   ↓
Aprendizaje
   ↓
Mejor conocimiento
   ↓
Mejor agente
   ↓
Mejor resultado
       ↺
</code></pre>
<p>Aquí la IA deja de ser únicamente una herramienta de producción.</p>
<p>Empieza a convertirse en parte del <strong>sistema de aprendizaje de la organización</strong>.</p>
<h1>14. Una arquitectura de referencia</h1>
<p>Si juntamos todas estas ideas, podemos imaginar una arquitectura bastante sencilla:</p>
<pre><code class="language-plaintext">                         ┌──────────────┐
                         │    HUMANO    │
                         └──────┬───────┘
                                │
                         decisiones críticas
                                │
                                ↓
┌──────────────┐        ┌──────────────┐
│  CONTEXTO Y  │ ─────→ │    AGENTE    │
│ CONOCIMIENTO │        └──────┬───────┘
└──────────────┘               │
                               ↓
                       ┌───────────────┐
                       │ HERRAMIENTAS  │
                       │ Y CAPACIDADES │
                       └───────┬───────┘
                               ↓
                       ┌───────────────┐
                       │ GOBERNANZA Y │
                       │ AUTORIZACIÓN  │
                       └───────┬───────┘
                               ↓
                             ACCIÓN
                               ↓
                           EVIDENCIA
                               ↓
                         VERIFICACIÓN
                               ↓
                            LEDGER
                               ↓
                          APRENDIZAJE
                               │
                               └────────→ CONTEXTO
</code></pre>
<p>Cada componente responde una pregunta diferente.</p>
<h3>Contexto</h3>
<blockquote>
<p>¿Qué sabemos y qué ocurrió?</p>
</blockquote>
<h3>Herramientas</h3>
<blockquote>
<p>¿Qué puede hacer el agente?</p>
</blockquote>
<h3>Gobernanza</h3>
<blockquote>
<p>¿Qué está autorizado a hacer?</p>
</blockquote>
<h3>Evidencia</h3>
<blockquote>
<p>¿Cómo sabemos qué ocurrió?</p>
</blockquote>
<h3>Verificación</h3>
<blockquote>
<p>¿Podemos confiar en el resultado?</p>
</blockquote>
<h3>Ledger</h3>
<blockquote>
<p>¿Podemos reconstruirlo después?</p>
</blockquote>
<h3>Aprendizaje</h3>
<blockquote>
<p>¿Qué deberíamos hacer diferente la próxima vez?</p>
</blockquote>
<h1>15. ¿Cómo lo llevaría a producción?</h1>
<p>Y aquí está la parte práctica.</p>
<p>No empezaría construyendo una plataforma gigantesca de agentes.</p>
<p>Empezaría mucho más simple.</p>
<h3>Fase 1 — Agente + contexto</h3>
<p>Un agente que pueda recuperar información confiable.</p>
<pre><code class="language-plaintext">Agente
 ↓
Knowledge
 ↓
Contexto
</code></pre>
<h3>Fase 2 — Herramientas</h3>
<p>Definir claramente qué puede hacer.</p>
<pre><code class="language-plaintext">Agente
 ↓
Tools
 ↓
APIs
</code></pre>
<h3>Fase 3 — Autorización</h3>
<p>Decidir qué herramientas puede utilizar y bajo qué condiciones.</p>
<pre><code class="language-plaintext">Agent
 ↓
Policy
 ↓
Tool
</code></pre>
<h3>Fase 4 — Evidencia</h3>
<p>Registrar las acciones importantes.</p>
<pre><code class="language-plaintext">Action
 ↓
Evidence
 ↓
Audit
</code></pre>
<h3>Fase 5 — Verificación</h3>
<p>Comprobar automáticamente los resultados cuando sea posible.</p>
<pre><code class="language-plaintext">Action
 ↓
Result
 ↓
Verifier
</code></pre>
<h3>Fase 6 — Autonomía gradual</h3>
<p>Permitir más autonomía solamente cuando exista evidencia suficiente.</p>
<pre><code class="language-plaintext">Manual
  ↓
Approval
  ↓
Supervised
  ↓
Autonomous
</code></pre>
<h3>Fase 7 — Aprendizaje</h3>
<p>Capturar lo que funcionó y lo que no.</p>
<pre><code class="language-plaintext">Execution
 ↓
Verification
 ↓
Learning
 ↓
Knowledge
</code></pre>
<p>Y volver a comenzar.</p>
<hr />
<h1>Conclusión</h1>
<p>Creo que estamos entrando en una etapa donde construir un agente ya no significa simplemente elegir un buen modelo y conectarlo a algunas herramientas.</p>
<p>El verdadero desafío aparece cuando queremos que ese agente pueda <strong>actuar en el mundo real</strong>.</p>
<p>En ese momento necesitamos responder preguntas mucho más difíciles:</p>
<blockquote>
<p>¿Qué sabe?</p>
</blockquote>
<blockquote>
<p>¿De dónde lo sabe?</p>
</blockquote>
<blockquote>
<p>¿Qué puede hacer?</p>
</blockquote>
<blockquote>
<p>¿Qué está autorizado a hacer?</p>
</blockquote>
<blockquote>
<p>¿Por qué confiamos en él?</p>
</blockquote>
<blockquote>
<p>¿Qué evidencia produjo?</p>
</blockquote>
<blockquote>
<p>¿Quién verifica esa evidencia?</p>
</blockquote>
<blockquote>
<p>¿Cuándo necesitamos a un humano?</p>
</blockquote>
<blockquote>
<p>¿Qué aprendimos después de equivocarnos?</p>
</blockquote>
<p>Y todas esas preguntas nos llevan a una conclusión:</p>
<p><strong>La autonomía no es el punto final de la arquitectura agentic.</strong></p>
<p>Es una consecuencia de haber construido suficiente contexto, confianza, evidencia, gobernanza y mecanismos de verificación.</p>
<p>Podemos resumirlo así:</p>
<pre><code class="language-plaintext">             CONTEXTO
                 ↓
            CAPACIDADES
                 ↓
           AUTORIZACIÓN
                 ↓
              ACCIÓN
                 ↓
             EVIDENCIA
                 ↓
           VERIFICACIÓN
                 ↓
            CONFIANZA
                 ↓
            AUTONOMÍA
                 ↓
           APRENDIZAJE
                 │
                 └──────────→ CONTEXTO
</code></pre>
<p>Y quizá el objetivo final no sea conseguir que la IA haga todo por nosotros.</p>
<p>Quizá sea algo mucho más interesante:</p>
<blockquote>
<p><strong>Construir organizaciones que sean mejores cada vez que hacen algo.</strong></p>
</blockquote>
<p>Una organización donde los agentes no solamente producen resultados, sino que ayudan a conservar el contexto, aprender de los errores, verificar las decisiones y aumentar gradualmente su autonomía.</p>
<p>Porque al final, el verdadero salto no es pasar de:</p>
<p><strong>humano → IA</strong></p>
<p>sino pasar de:</p>
<p><strong>IA que responde</strong></p>
<p>a:</p>
<p><strong>sistemas que actúan, verifican y aprenden.</strong></p>
]]></content:encoded></item><item><title><![CDATA[El hospital ya sabe quién ve qué. El problema es que la IA no.]]></title><description><![CDATA[Un hospital no reparte copias de todo. Un potasio crítico despierta a la cama 214, no a la directora. Una nota de psiquiatría no está disponible para…]]></description><link>https://joedayz.hashnode.dev/el-hospital-ya-sabe-qui-n-ve-qu-el-problema-es-que-la-ia-no</link><guid isPermaLink="true">https://joedayz.hashnode.dev/el-hospital-ya-sabe-qui-n-ve-qu-el-problema-es-que-la-ia-no</guid><category><![CDATA[joedayz]]></category><category><![CDATA[genai]]></category><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Sun, 20 Sep 2026 03:45:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/33d9f110-c950-4c8d-b132-c0d32b98873f.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Un hospital no reparte copias de todo.</p>
<p>Un potasio crítico despierta a la cama 214, no a la directora. Una nota de psiquiatría no está disponible para cualquiera solo porque técnicamente exista en el sistema.</p>
<p>Con personas, esto parece obvio.</p>
<p>Pero cuando introducimos IA aparece una pregunta incómoda:</p>
<blockquote>
<p><strong>¿Cómo hacemos para que la IA vea solamente lo que le corresponde?</strong></p>
</blockquote>
<p>Este post cuenta una noche de guardia para explicar una idea sencilla: <strong>ruteo gobernado</strong>.</p>
<p>Quién puede ver qué, quién necesita verlo, por qué canal debe recibirlo y qué evidencia queda.</p>
<p>Y hay algo importante en la demo que acompaña este artículo:</p>
<p><strong>no llama a ningún modelo.</strong></p>
<p>No es una limitación. Es la lección.</p>
<p>La IA entra después, y solo con lo que ya le llegó.</p>
<p><strong>Demo:</strong> <a href="https://github.com/joedayz/governed-agents/tree/main/clinica-gobernada">https://github.com/joedayz/governed-agents/tree/main/clinica-gobernada</a></p>
<h2>Una noche. Una cama.</h2>
<p>Son las <strong>02:14</strong> en la Clínica San Mateo.</p>
<p>En la cama <strong>214</strong> está Ana López, 67 años, con una insuficiencia cardíaca descompensada.</p>
<p>Durante la guardia tenemos médicos, enfermeras y algunos agentes de software.</p>
<p>Por ahora, piensa en los agentes como compañeros de turno con un buzón.</p>
<p>Todavía no razonan.</p>
<p>Solo reciben información o no la reciben.</p>
<p>La regla tiene dos preguntas:</p>
<blockquote>
<p><strong>¿Puede verlo?</strong> <strong>¿Debe verlo ahora?</strong></p>
</blockquote>
<p>La primera es permiso.</p>
<p>La segunda es necesidad.</p>
<p>Solo cuando ambas respuestas son sí, el dato se entrega.</p>
<p>Y existen únicamente dos canales:</p>
<ul>
<li><p>🚨 <strong>Urgente:</strong> buscapersonas. No espera.</p>
</li>
<li><p>📋 <strong>Resumen:</strong> pase de guardia. Puede esperar.</p>
</li>
</ul>
<p>Eso es prácticamente todo el motor:</p>
<blockquote>
<p><strong>¿Entró por el sistema? → ¿Qué tipo de dato es? → ¿Puede? → ¿Debe? → ¿Urgente o resumen? → ¿Queda prueba?</strong></p>
</blockquote>
<hr />
<h2>Primero: qué NO entra</h2>
<p>Antes de hacer cualquier cosa con IA, hay datos que ni siquiera deberían entrar al flujo.</p>
<p>Por ejemplo:</p>
<blockquote>
<p>📱 <strong>Foto de una receta casera enviada por WhatsApp por la hija de Ana.</strong></p>
</blockquote>
<p>Llegó desde un celular personal, no desde un sistema de la clínica.</p>
<p>Por tanto, queda fuera.</p>
<p>No importa que un agente pueda leer la imagen.</p>
<p>No importa que parezca información útil.</p>
<p><strong>Si no entró por el canal autorizado, el agente no debería poder encontrarla.</strong></p>
<p>Este filtro ocurre antes de cualquier modelo.</p>
<hr />
<h2>Cinco hechos. Cero IA.</h2>
<p>Ahora ejecutamos la demo.</p>
<h3>1. Potasio 6.8</h3>
<p>Es un valor crítico.</p>
<ul>
<li><p><strong>Enfermera Ruiz:</strong> 🚨 urgente. Está en la cama 214.</p>
</li>
<li><p><strong>Dra. Vargas:</strong> 🚨 urgente. Es la médica tratante.</p>
</li>
<li><p><strong>Dr. Mendoza:</strong> retenido. Puede verlo, pero no está a cargo de esa cama.</p>
</li>
<li><p><strong>Dra. Torres:</strong> no pasa. La dirección no necesita despertarse por cada laboratorio.</p>
</li>
<li><p><strong>Agentes:</strong> no les corresponde.</p>
</li>
</ul>
<p>Un K+ de 6.8 no es un correo.</p>
<p><strong>Es un buscapersonas.</strong></p>
<p>El hospital ya sabe quién debe despertarse.</p>
<p>La IA no debería tener que inventarlo.</p>
<h3>2. Nueva guía de diuréticos</h3>
<p>La misma información puede tener diferentes canales.</p>
<ul>
<li><p><strong>Vargas:</strong> 🚨 urgente, porque prescribe durante el turno.</p>
</li>
<li><p><strong>Agente de protocolos:</strong> 📋 resumen, porque puede procesarla después.</p>
</li>
</ul>
<p>Aquí aparece una distinción importante:</p>
<blockquote>
<p><strong>Tener permiso no significa que te corresponda recibir algo ahora.</strong></p>
</blockquote>
<h3>3. Pedido de auditoría SUSALUD</h3>
<p>La directora tiene permisos relacionados con calidad.</p>
<p>Pero eso no significa que necesite recibir todo el documento crudo.</p>
<p>Necesita el <strong>resultado de la auditoría</strong>, no necesariamente cada archivo que llegó.</p>
<p>Si mandamos todo a todos los que técnicamente pueden verlo, terminamos creando otro problema:</p>
<p><strong>demasiada información.</strong></p>
<h3>4. 14 dosis de espironolactona sin registro</h3>
<p>El agente de farmacia debe enterarse.</p>
<p>→ 🚨 <strong>Urgente</strong></p>
<p>El agente de historias necesita esa información para completar el expediente, pero no tiene permiso para acceder directamente a farmacia.</p>
<p>Tenemos:</p>
<blockquote>
<p><strong>Necesario, pero bloqueado.</strong></p>
</blockquote>
<p>Entonces interviene Mendoza.</p>
<p>Autoriza la excepción.</p>
<p>Queda un recibo.</p>
<p>El humano no vigila todo el stream.</p>
<p><strong>Firma el hueco.</strong></p>
<h3>5. La nota de psiquiatría</h3>
<p>La historia contiene una nota relacionada con riesgo por litio.</p>
<p>Normalmente, la guardia no puede leerla.</p>
<p>Pero Vargas necesita esa información para tomar una decisión clínica.</p>
<p>Tenemos otra vez:</p>
<blockquote>
<p><strong>Necesaria, pero bloqueada.</strong></p>
</blockquote>
<p>Mendoza autoriza.</p>
<p>La nota llega a Vargas.</p>
<p>No llega a Torres.</p>
<p>No llega a toda la guardia.</p>
<p>Y queda registrada la excepción.</p>
<p>El mismo documento puede tener tres destinos:</p>
<ul>
<li><p>alguien <strong>no puede</strong> verlo;</p>
</li>
<li><p>alguien <strong>puede</strong>, pero no necesita recibirlo;</p>
</li>
<li><p>alguien <strong>necesita</strong> verlo y obtiene una autorización puntual.</p>
</li>
</ul>
<p>Eso es gobierno.</p>
<p>Y hasta aquí:</p>
<p><strong>cero IA.</strong></p>
<h2>Entonces, ¿dónde entra la IA?</h2>
<p>Ahora llegamos al último paso de la demo.</p>
<p>El dato ya pasó por las reglas.</p>
<p>Ya sabemos quién puede recibirlo.</p>
<p>Ya sabemos quién lo necesita.</p>
<p>Ya sabemos por qué canal llegó.</p>
<p>Y quedó evidencia.</p>
<p><strong>El dato entra al buzón del agente.</strong></p>
<p>Recién aquí aparece la IA.</p>
<p>Y ahora sí puede hacer su trabajo:</p>
<ul>
<li><p>resumir;</p>
</li>
<li><p>clasificar;</p>
</li>
<li><p>preparar una alerta;</p>
</li>
<li><p>organizar información;</p>
</li>
<li><p>proponer una respuesta.</p>
</li>
</ul>
<p>Pero hay una frontera:</p>
<blockquote>
<p><strong>Lo que no llegó al buzón, el agente no debería poder utilizarlo.</strong></p>
</blockquote>
<p>Por ejemplo:</p>
<table>
<thead>
<tr>
<th>Le llegó</th>
<th>Puede hacer</th>
<th>No puede hacer</th>
</tr>
</thead>
<tbody><tr>
<td>Nueva guía → protocolos</td>
<td>Crear una lista de pacientes afectados</td>
<td>Avisar a Torres sobre el K+ de Ana</td>
</tr>
<tr>
<td>14 dosis → farmacia</td>
<td>Organizar camas y turnos a revisar</td>
<td>Abrir la nota de psiquiatría</td>
</tr>
<tr>
<td>Nota autorizada → Vargas</td>
<td>Analizar su contenido</td>
<td>Buscar en todas las historias clínicas</td>
</tr>
</tbody></table>
<p>La IA puede trabajar sobre el dato.</p>
<p><strong>No decide quién tiene derecho a recibirlo.</strong></p>
<hr />
<h2>El error clásico: relevancia ≠ autoridad</h2>
<p>Una IA “útil” podría pensar:</p>
<blockquote>
<p>“El K+ 6.8 parece muy importante. Se lo mando a todos.”</p>
</blockquote>
<p>O:</p>
<blockquote>
<p>“Esta receta de WhatsApp habla del paciente. La agrego al expediente.”</p>
</blockquote>
<p>O:</p>
<blockquote>
<p>“Encontré la palabra ‘litio’ en una nota de psiquiatría. La incluyo en el resumen de planta.”</p>
</blockquote>
<p>Ninguna de esas acciones necesita mala intención.</p>
<p>El problema es otro:</p>
<blockquote>
<p><strong>confundir relevancia con autoridad.</strong></p>
</blockquote>
<p>Un modelo puede detectar que algo es importante.</p>
<p>Eso no significa que tenga permiso para utilizarlo.</p>
<p>Por eso el prompt:</p>
<blockquote>
<p>“Por favor, ten cuidado con los datos sensibles”</p>
</blockquote>
<p>no sustituye una política de acceso.</p>
<hr />
<h2>Dos capas</h2>
<p>Podemos resumir toda la arquitectura en dos capas.</p>
<h3>Capa 1 — Gobierno</h3>
<p><strong>Qué entra → quién puede verlo → quién debe verlo → canal → autorización → recibo</strong></p>
<h3>Capa 2 — IA</h3>
<p><strong>Resume → clasifica → organiza → propone</strong></p>
<p>El error es darle al modelo las dos responsabilidades.</p>
<p>Que decida qué información es relevante <strong>y</strong> quién debería recibirla.</p>
<p>El hospital no funciona así.</p>
<p>La IA tampoco debería.</p>
<h2>¿Y si ponemos más IA?</h2>
<p>¿Cuánto trabajo delegamos a la IA?</p>
<p>Hay que hablar de escalamiento.</p>
<p>Podemos empezar con:</p>
<ul>
<li><p>un agente que resume protocolos;</p>
</li>
<li><p>luego incorporar farmacia;</p>
</li>
<li><p>después automatizar más tareas rutinarias;</p>
</li>
<li><p>finalmente delegar gran parte del trabajo que no requiere juicio clínico irreversible.</p>
</li>
</ul>
<p>La pregunta no es solamente:</p>
<blockquote>
<p><strong>“¿Cuánta IA podemos poner?”</strong></p>
</blockquote>
<p>Es:</p>
<blockquote>
<p><strong>“¿Podemos aumentar la automatización sin perder el control sobre la información?”</strong></p>
</blockquote>
<p>Con gobierno, podemos aumentar el trabajo de los agentes sin cambiar la regla fundamental:</p>
<p><strong>quién puede ver qué, por qué y con qué evidencia.</strong></p>
<h2>La demo en tres minutos</h2>
<p>Si quieres mostrarla, no necesitas explicar toda la arquitectura.</p>
<p>Pregunta primero:</p>
<blockquote>
<p><strong>“Si llega un potasio de 6.8 a las 02:14, ¿quién se despierta?”</strong></p>
</blockquote>
<p>Luego pulsa <strong>Paso</strong> y muestra los buzones.</p>
<p>Cuando llegues a la nota de psiquiatría:</p>
<blockquote>
<p><strong>“Aquí alguien necesita el dato, pero está bloqueado. ¿Qué hacemos?”</strong></p>
</blockquote>
<p>Muestra la autorización humana.</p>
<p>Y finalmente:</p>
<blockquote>
<p><strong>“Hasta aquí no hubo IA.”</strong></p>
</blockquote>
<p>Último paso:</p>
<blockquote>
<p><strong>“Ahora sí. Pero solo con lo que ya le llegó.”</strong></p>
</blockquote>
<p>En la demo puedes cambiar las etiquetas a <strong>Atlas (Thor)</strong> para mostrar:</p>
<ul>
<li><p><code>may-see</code> → puede verlo;</p>
</li>
<li><p><code>should-see</code> → debería recibirlo;</p>
</li>
<li><p><code>HITL grant</code> → un humano autorizó la excepción.</p>
</li>
</ul>
<p><strong>Espacio</strong> = Paso <strong>Reiniciar</strong> = volver al inicio.</p>
<hr />
<h2>Qué NO es esta demo</h2>
<p>Para no vender de más:</p>
<ul>
<li><p>No es un producto clínico.</p>
</li>
<li><p>No es un HIS.</p>
</li>
<li><p>No hay un LLM detrás de los agentes de la demo.</p>
</li>
<li><p>Los agentes son buzones con un rol.</p>
</li>
<li><p>El último paso usa texto escrito a mano para mostrar dónde entraría la IA.</p>
</li>
<li><p>Un hospital real tendrá muchos más roles y excepciones.</p>
</li>
</ul>
<p>Pero el principio permanece:</p>
<blockquote>
<p><strong>puede ∩ debe → canal → recibo</strong></p>
</blockquote>
<hr />
<h1>Cierre</h1>
<p>Un hospital no es un grupo de WhatsApp con bata.</p>
<p>Un dato entra por el sistema correcto.</p>
<p>Llega a quien lo necesita.</p>
<p>Si existe un hueco, un humano autorizado interviene.</p>
<p>Y mañana podemos reconstruir la cadena.</p>
<p>Eso ya lo saben los hospitales.</p>
<p>Lo que cambia con los agentes de IA es que ahora tenemos más actores capaces de procesar información.</p>
<p>Por eso la primera pregunta no debería ser:</p>
<blockquote>
<p><strong>“¿Qué tan inteligente puede ser nuestro agente?”</strong></p>
</blockquote>
<p>Debería ser:</p>
<blockquote>
<p><strong>“¿Qué información tiene permitido recibir?”</strong></p>
</blockquote>
<p>La parte que reparte <strong>no puede ser el modelo</strong>.</p>
<p>La IA entra después.</p>
<p>Trabaja con lo que recibió.</p>
<p>Y el día que alguien pregunte:</p>
<blockquote>
<p><strong>“¿Por qué este agente vio este dato?”</strong></p>
</blockquote>
<p>la respuesta no debería estar en un prompt.</p>
<p><strong>Debería estar en un recibo.</strong></p>
<hr />
<h3>Recursos</h3>
<p><strong>Demo:</strong> <a href="https://github.com/joedayz/governed-agents/tree/main/clinica-gobernada">https://github.com/joedayz/governed-agents/tree/main/clinica-gobernada</a></p>
<p><strong>Sunstone Atlas:</strong> <a href="https://sunstone.exoreaction.com/sunstone-atlas-simulator.html">https://sunstone.exoreaction.com/sunstone-atlas-simulator.html</a></p>
<p><strong>Post hermano — agente en Python:</strong> <a href="https://blog.joedayz.pe/agente1/POST.md">https://blog.joedayz.pe/agente1/POST.md</a></p>
]]></content:encoded></item><item><title><![CDATA[KCP explicado fácil]]></title><description><![CDATA[Si alguna vez sentiste que tus agentes "saben mucho" pero igual toman malas decisiones, este artículo es para ti. Porque el problema no suele ser falta de…]]></description><link>https://joedayz.hashnode.dev/kcp-explicado-f-cil</link><guid isPermaLink="true">https://joedayz.hashnode.dev/kcp-explicado-f-cil</guid><category><![CDATA[kcp]]></category><category><![CDATA[joedayz]]></category><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Sun, 30 Aug 2026 03:53:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/1980742d-6a7a-4daa-aa65-3fb25784972c.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Si alguna vez sentiste que tus agentes "saben mucho" pero igual toman malas decisiones, este artículo es para ti.</p>
<p>Porque el problema no suele ser falta de información. El problema suele ser <strong>falta de contexto gobernado</strong>.</p>
<p>Y ahí entra <strong>KCP (Knowledge Context Protocol)</strong>.</p>
<p>Imagina una clínica moderna. Llega un paciente con síntomas difusos: fatiga, dolor, fiebre intermitente. No puedes tratarlo solo con "lo primero que aparezca en Google".</p>
<p>Necesitas:</p>
<ol>
<li><p>Historia clínica válida</p>
</li>
<li><p>Protocolos autorizados</p>
</li>
<li><p>Diagnóstico estructurado</p>
</li>
<li><p>Trazabilidad de decisiones</p>
</li>
<li><p>Seguimiento continuo</p>
</li>
</ol>
<p>En software con IA pasa lo mismo. KCP hace exactamente eso: convierte conocimiento disperso en un sistema confiable de decisión.</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/1d166588-802c-460a-ae2f-3ad8a477fdbd.jpg" alt="" style="display:block;margin:0 auto" />

<h2><strong>La analogía central (simple y poderosa)</strong></h2>
<p><strong>KCP es la historia clínica gobernada del sistema.</strong></p>
<ul>
<li><p><strong>RAG</strong> pregunta: "¿qué texto parece relevante?"</p>
</li>
<li><p><strong>KCP</strong> pregunta: "¿qué conocimiento es autoridad, está vigente y puedo usar para actuar?"</p>
</li>
</ul>
<p>KCP no reemplaza memoria ni código. Los ordena bajo reglas de validez, permisos y evidencia.</p>
<h2><strong>Caso clínico realista: "Incidente de despliegue con riesgo de cumplimiento"</strong></h2>
<h3><strong>Escenario</strong></h3>
<p>Un equipo detecta que una actualización dejó un servicio inestable. Hay presión por arreglar rápido, pero también hay riesgo de tocar datos sensibles y romper compliance.</p>
<h3><strong>Objetivo</strong></h3>
<p>Resolver el incidente sin perder control, sin improvisar y con evidencia auditable.</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/3c26ad33-4e75-4f80-a236-c17f6abeb5eb.jpg" alt="" style="display:block;margin:0 auto" />

<h2><strong>Cómo participa cada herramienta del ecosistema KCP</strong></h2>
<h3><strong>1) Recepción y triaje →</strong> <code>kcp-hooks</code></h3>
<p>Antes de actuar, el sistema enruta el prompt, recupera contexto relevante y limpia ruido o manipulación.</p>
<p><strong>Analogía:</strong> recepción clínica y enfermería de admisión.</p>
<hr />
<h3><strong>2) Historia clínica longitudinal →</strong> <code>kcp-memory</code></h3>
<p>Recupera incidentes parecidos, decisiones previas y comandos usados antes.</p>
<p><strong>Analogía:</strong> expediente del paciente a lo largo del tiempo.</p>
<hr />
<h3><strong>3) Apoyo diagnóstico estructural → Synthesis</strong></h3>
<p>Analiza el repositorio y el código para ubicar módulos afectados, dependencias y patrones.</p>
<p><strong>Analogía:</strong> laboratorio e imagenología (rayos X / resonancia) del sistema.</p>
<hr />
<h3><strong>4) Decisión clínica del plan →</strong> <code>kcp-agent</code></h3>
<p>Selecciona qué unidades de conocimiento cargar desde <code>knowledge.yaml</code> usando criterios explícitos: audiencia, vigencia, relevancia, dependencias y límites.</p>
<p><strong>Analogía:</strong> médico tratante que decide protocolo.</p>
<hr />
<h3><strong>5) Comité de seguridad y permisos →</strong> <code>kcp-harness</code> <strong>y</strong> <code>pi-kcp</code></h3>
<p>Valida si cada acción está autorizada y dentro del alcance permitido.</p>
<p><strong>Analogía:</strong> comité clínico que impide intervenciones fuera de protocolo.</p>
<hr />
<h3><strong>6) Ejecución asistida y registro →</strong> <code>kcp-commands</code></h3>
<p>Guía comandos, filtra ruido de salida y registra eventos operativos.</p>
<p><strong>Analogía:</strong> enfermería durante tratamiento y hoja de evolución.</p>
<hr />
<h3><strong>7) Calidad del conocimiento →</strong> <code>kcp-forge</code></h3>
<p>Evita drift, referencias rotas y manifiestos degradados.</p>
<p><strong>Analogía:</strong> control de calidad hospitalario.</p>
<hr />
<h3><strong>8) Conocimiento externo del paciente →</strong> <code>kcp-triage</code></h3>
<p>Si hay una API o servicio de terceros involucrado, lo transforma en conocimiento KCP utilizable.</p>
<p><strong>Analogía:</strong> interconsulta con hospital externo y homologación de datos.</p>
<hr />
<h3><strong>9) Indicadores y seguimiento →</strong> <code>kcp-dashboard</code></h3>
<p>Mide efectividad, retries, cobertura, salud del sistema y continuidad.</p>
<p><strong>Analogía:</strong> tablero clínico de calidad y resultados.</p>
<hr />
<h3><strong>10) Formación del equipo →</strong> <code>kcp-playground</code></h3>
<p>Permite enseñar visualmente cómo decide el agente y por qué.</p>
<p><strong>Analogía:</strong> simulador médico para entrenamiento.</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/ca7398d5-d2c0-4989-a5f5-5643b935c3e7.jpg" alt="" style="display:block;margin:0 auto" />

<h2><strong>Dónde entra</strong> <code>knowledge.yaml</code> <strong>en este caso</strong></h2>
<p><code>knowledge.yaml</code> es el mapa clínico del conocimiento. No solo lista documentos: define intención, audiencia, vigencia, relaciones y dependencias.</p>
<p>Eso permite responder con precisión:</p>
<ul>
<li><p>¿Qué debo leer primero?</p>
</li>
<li><p>¿Qué está vigente hoy?</p>
</li>
<li><p>¿Qué está deprecado?</p>
</li>
<li><p>¿Qué puedo ejecutar y qué no?</p>
</li>
</ul>
<p>Sin eso, el agente adivina. Con eso, navega con criterio.</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/0a78313b-b3e3-4444-befb-d6d554428626.jpg" alt="" style="display:block;margin:0 auto" />

<h2><strong>¿Por qué esto importa?</strong></h2>
<p>Porque automatizar sin gobernanza produce velocidad frágil. KCP busca <strong>velocidad confiable</strong>.</p>
<p>No es "más herramientas". Es una arquitectura para que agentes de IA trabajen con:</p>
<ul>
<li><p>contexto correcto</p>
</li>
<li><p>límites explícitos</p>
</li>
<li><p>decisiones defendibles</p>
</li>
<li><p>evidencia auditable</p>
</li>
</ul>
<h2><strong>Cierre</strong></h2>
<p><strong>KCP no reemplaza la memoria ni el código; le da al agente una forma de distinguir relevancia de autoridad y actuar solo dentro de lo permitido.</strong></p>
<p>Y cuando sumas <strong>Synthesis</strong> como apoyo diagnóstico, dejas de operar a ciegas: entiendes el sistema antes de intervenir.</p>
<p>Ese es el salto: de "IA que responde" a <strong>IA que decide con criterio y gobernanza</strong>.</p>
<p>Enjoy!</p>
<p>Joe</p>
]]></content:encoded></item><item><title><![CDATA[Cómo orquestar un equipo de agentes con KCP sin perder el control]]></title><description><![CDATA[Si ya tienes varios agentes colaborando, el problema no suele ser crear otro agente. El problema real es decidir qué conocimiento cargar y qué acciones…]]></description><link>https://joedayz.hashnode.dev/c-mo-orquestar-un-equipo-de-agentes-con-kcp-sin-perder-el-control</link><guid isPermaLink="true">https://joedayz.hashnode.dev/c-mo-orquestar-un-equipo-de-agentes-con-kcp-sin-perder-el-control</guid><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Fri, 28 Aug 2026 04:44:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/4ae40dee-291c-4df6-aa26-85d191e15855.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Si ya tienes varios agentes colaborando, el problema no suele ser crear otro agente. El problema real es <strong>decidir qué conocimiento cargar y qué acciones permitir</strong> sin <strong>terminar con lógica casera difícil de auditar</strong>.</p>
<p>En esta demo resolví ese problema con dos piezas del ecosistema KCP: <code>kcp-agent</code> para planificar y <code>kcp-harness</code> para gobernar la ejecución. El resultado es un flujo donde el sistema decide qué unidades son relevantes para un caso clínico y, por separado, valida en runtime si cada agente puede leer o escribir donde dice que puede.</p>
<p>Source Code: <a href="https://github.com/joedayz/governed-agents.git">https://github.com/joedayz/governed-agents.git</a></p>
<h2><strong>El problema: agentes útiles, pero sin gobernanza clara</strong></h2>
<p>Un equipo de agentes puede verse convincente en una demo aunque por debajo tenga reglas frágiles:</p>
<ul>
<li><p>un planificador ad hoc que decide qué cargar;</p>
</li>
<li><p>permisos implícitos repartidos en prompts;</p>
</li>
<li><p>validaciones que viven "en el papel" pero no en la ejecución real;</p>
</li>
<li><p>poca trazabilidad sobre por qué una acción fue permitida o denegada.</p>
</li>
</ul>
<p>Eso funciona hasta que un agente intenta hacer algo fuera de alcance.</p>
<p>En este proyecto usé un caso simple de triaje de citas clínicas para mostrar una alternativa más robusta: <strong>separar planificación y control de ejecución</strong>.</p>
<h2><strong>La idea central</strong></h2>
<p>La arquitectura se apoya en una división muy clara:</p>
<table>
<thead>
<tr>
<th><strong>Pieza</strong></th>
<th><strong>Responsabilidad</strong></th>
</tr>
</thead>
<tbody><tr>
<td><code>kcp-agent</code></td>
<td>Decide qué unidades del manifiesto (skills) son relevantes para una tarea.</td>
</tr>
<tr>
<td><code>kcp-harness</code></td>
<td>Decide si una acción concreta está permitida según el <code>action_scope</code>.</td>
</tr>
<tr>
<td><code>orquestador.ts</code></td>
<td>Conecta ambas decisiones en una ejecución de extremo a extremo.</td>
</tr>
</tbody></table>
<p>Dicho de forma simple: <code>kcp-agent</code> responde <strong>qué hace falta cargar</strong> y <code>kcp-harness</code> responde <strong>qué se puede hacer con eso</strong>.</p>
<h2><strong>El caso de ejemplo</strong></h2>
<p>La demo procesa un caso clínico como:</p>
<pre><code class="language-plaintext">fiebre leve y dolor de garganta
</code></pre>
<img src="http://localhost:63342/markdownPreview/1267483732//Users/josediaz/Projects/JoeDayz/kcp/equipo-agentes-con-kcp/docs" alt="" style="display:block;margin:0 auto" />

<p>Ese dato entra al orquestador y activa una corrida completa. Importa aclarar algo que suele confundir al ver la salida por primera vez:</p>
<blockquote>
<p>Cada ejecución procesa <strong>un solo caso clínico</strong>. Las "unidades cargadas" no son otros casos, sino skills y documentos que <code>kcp-agent</code> consideró relevantes para ese mismo caso.</p>
</blockquote>
<h2><strong>Cómo se modela el conocimiento</strong></h2>
<p>El manifiesto <code>knowledge.yaml</code> combina tres tipos de unidades:</p>
<ol>
<li><p>documentos de conocimiento como <code>protocolo-triaje</code> y <code>faq-agenda</code>;</p>
</li>
<li><p>skills gobernadas como <code>retriever-skill</code>, <code>assessor-skill</code>, <code>drafter-skill</code> y <code>executor-skill</code>;</p>
</li>
<li><p>un playbook compuesto llamado <code>gestionar-cita-clinica</code>.</p>
</li>
</ol>
<p>Lo interesante no es solo que todo esté descrito en el manifiesto, sino que cada skill declara su propio <code>action_scope</code>. Por ejemplo, <code>executor-skill</code> puede usar <code>write_file</code>, pero solo dentro de <code>salidas/</code>.</p>
<h2><strong>Diagrama 1: vista general de la orquestación</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/e7341706-40d4-4ad6-81b5-73916342a515.png" alt="" style="display:block;margin:0 auto" />

<p>Este diagrama resume la separación de responsabilidades: primero se calcula el plan y luego se validan las acciones observadas.</p>
<h2><strong>Diagrama 2: planificación con</strong> <code>kcp-agent</code></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/737efc1b-4465-4fc1-8b90-72a8a4e22b7b.png" alt="" style="display:block;margin:0 auto" />

<p>Aquí no se ejecuta ninguna herramienta externa ni se toca el filesystem para efectos del caso. Solo se decide qué piezas vale la pena cargar.</p>
<p>En una corrida normal, la salida muestra unidades como:</p>
<ul>
<li><p><code>faq-agenda</code></p>
</li>
<li><p><code>gestionar-cita-clinica</code></p>
</li>
<li><p><code>retriever-skill</code></p>
</li>
<li><p><code>protocolo-triaje</code></p>
</li>
<li><p><code>assessor-skill</code></p>
</li>
<li><p><code>drafter-skill</code></p>
</li>
</ul>
<p>Y puede dejar otras como "ignoradas" si no son relevantes para la intención detectada.</p>
<h2><strong>Diagrama 3: control de acciones con</strong> <code>kcp-harness</code></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/efede684-455d-47d4-b3cb-777207a7bdb3.png" alt="" style="display:block;margin:0 auto" />

<p>Esta parte es la que convierte los permisos declarados en una frontera real de ejecución.</p>
<p>En la demo:</p>
<ul>
<li><p><code>retriever</code>, <code>assessor</code> y <code>drafter</code> leen archivos con <code>read_file</code>;</p>
</li>
<li><p><code>executor</code> escribe con <code>write_file</code>;</p>
</li>
<li><p>cualquier escritura fuera de <code>salidas/</code> queda fuera de alcance.</p>
</li>
</ul>
<h2><strong>Diagrama 4: ejecución normal</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/87c33618-7114-409c-b1fd-66910e418917.png" alt="" style="display:block;margin:0 auto" />

<p>Si todo cae dentro del alcance, el sistema registra el resultado final en <code>salidas/resultado.json</code>.</p>
<h2><strong>Diagrama 5: intento fuera de alcance</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/7949bfef-0ea4-4267-8b2f-86ab9b2d8c45.png" alt="" style="display:block;margin:0 auto" />

<p>Este es el punto más importante de la demo. La protección no depende de "que el agente se porte bien". Depende de una validación explícita y auditable en runtime.</p>
<h2><strong>Qué enseña esta demo en la práctica</strong></h2>
<p>Más allá del ejemplo clínico, hay cuatro lecciones útiles para cualquier sistema multiagente:</p>
<ol>
<li><p><strong>No mezcles selección de contexto con permisos de ejecución.</strong> Son problemas distintos.</p>
</li>
<li><p><strong>Declara el alcance junto al skill.</strong> Si un agente puede escribir, define exactamente dónde.</p>
</li>
<li><p><strong>Haz que el runtime adjudique cada acción.</strong> El permiso debe verificarse cuando ocurre la acción, no solo cuando diseñas el prompt.</p>
</li>
<li><p><strong>Conserva trazabilidad.</strong> Un buen veredicto no solo bloquea: también explica por qué.</p>
</li>
</ol>
<h2><strong>Comandos de la demo</strong></h2>
<pre><code class="language-typescript">npm install
npm run validate
npm run harness:check
npm run orquestar
npx tsx orquestador.ts "dolor de pecho y dificultad para respirar"
npm run orquestar:romper-alcance
</code></pre>
<img src="http://localhost:63342/markdownPreview/1267483732//Users/josediaz/Projects/JoeDayz/kcp/equipo-agentes-con-kcp/docs" alt="" style="display:block;margin:0 auto" />

<h2><strong>Cuándo usar este patrón</strong></h2>
<p>Este enfoque vale especialmente la pena cuando tienes:</p>
<ul>
<li><p>múltiples agentes con responsabilidades separadas;</p>
</li>
<li><p>conocimiento distribuido en varios documentos o skills;</p>
</li>
<li><p>operaciones sensibles como escritura de archivos, llamadas a APIs o cambios de estado;</p>
</li>
<li><p>necesidad de explicar por qué una acción fue bloqueada.</p>
</li>
</ul>
<p>Si tu sistema todavía depende de prompts largos y permisos implícitos, KCP te da una forma más explícita de convertir esa coordinación en reglas verificables.</p>
<h2><strong>Cierre</strong></h2>
<p>La parte valiosa de esta demo no es que coordine cuatro agentes. La parte valiosa es que <strong>cada decisión importante queda separada, declarada y verificable</strong>.</p>
<p><code>kcp-agent</code> decide la relevancia. <code>kcp-harness</code> decide la conformidad. El orquestador solo conecta ambas piezas.</p>
<p>Esa separación hace que un sistema multiagente sea más fácil de entender, más fácil de auditar y mucho más difícil de romper por accidente.</p>
<p>Enjoy!</p>
<p>Joe</p>
]]></content:encoded></item><item><title><![CDATA[namespaces, require, tests, project structure y domain modeling]]></title><description><![CDATA[Esta semana vamos a pasar de “escribir funciones” a organizar un proyecto real. La meta es entender cómo se reparte el código en namespaces, cómo se…]]></description><link>https://joedayz.hashnode.dev/namespaces-require-tests-project-structure-y-domain-modeling</link><guid isPermaLink="true">https://joedayz.hashnode.dev/namespaces-require-tests-project-structure-y-domain-modeling</guid><category><![CDATA[Clojure]]></category><category><![CDATA[joedayz]]></category><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Fri, 28 Aug 2026 04:06:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/1af2d5ff-715f-4e16-8371-f14df8470da5.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Esta semana vamos a pasar de “escribir funciones” a <strong>organizar un proyecto real</strong>. La meta es entender cómo se reparte el código en namespaces, cómo se conectan con <code>require</code>, cómo se ordenan <code>src</code> y <code>test</code>, y cómo se modela un dominio con funciones puras.</p>
<p>La idea no es memorizar una receta. Es entender por qué esta estructura hace el proyecto más fácil de leer, probar y mantener.</p>
<h2><strong>1) Namespaces: la manera de ordenar el código</strong></h2>
<p>Un namespace (<code>ns</code>) es una forma de agrupar funciones relacionadas. En Clojure, normalmente cada archivo tiene un namespace, y ese namespace debe coincidir con la ruta del archivo.</p>
<pre><code class="language-java">;; src/clojure_saveme/week3/domain.clj
(ns clojure-saveme.week3.domain)
</code></pre>
<p>Piensa en esto así:</p>
<ul>
<li><p>el archivo dice <strong>dónde vive</strong> el código</p>
</li>
<li><p>el namespace dice <strong>cómo lo llamas</strong></p>
</li>
<li><p>juntos te ayudan a no mezclar responsabilidades</p>
</li>
</ul>
<p>Regla práctica:</p>
<ul>
<li><p><code>src/clojure_saveme/week3/domain.clj</code></p>
</li>
<li><p><code>clojure-saveme.week3.domain</code></p>
</li>
</ul>
<p>La carpeta usa <code>_</code> y el namespace usa <code>-</code> porque así se traduce la ruta al nombre lógico del módulo.</p>
<h2><strong>2)</strong> <code>require</code><strong>: conectar módulos entre sí</strong></h2>
<p>Cuando un namespace necesita usar funciones de otro, lo trae con <code>:require</code>.</p>
<pre><code class="language-java">;; src/clojure_saveme/week3/core.clj
(ns clojure-saveme.week3.core  
  (:require [clojure-saveme.week3.domain :as domain]))

(defn checkout  
  [raw-order min-total discount-percentage]
  (let [order (domain/build-order raw-order)]
    (if (domain/eligible-for-discount? order min-total)
      (domain/mark-paid (domain/apply-discount order discount-percentage))
      (domain/mark-paid order))))
</code></pre>
<img src="http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Qué está pasando aquí:</p>
<ol>
<li><p><code>core</code> no reescribe la lógica del negocio</p>
</li>
<li><p><code>core</code> llama a <code>domain</code></p>
</li>
<li><p><code>:as domain</code> evita repetir el nombre completo cada vez</p>
</li>
</ol>
<p>Eso mismo se ve en los tests: un namespace de pruebas también hace <code>require</code> del código que quiere verificar.</p>
<h2><strong>3) Estructura del proyecto: separar por responsabilidad</strong></h2>
<p>Cuando el proyecto crece, ya no conviene poner todo en un solo archivo. La idea es separar por intención:</p>
<pre><code class="language-java">src/clojure_saveme/
  week3/
    domain.clj
    core.clj
test/clojure_saveme/
  week3/
    domain_test.clj
    core_test.clj
</code></pre>
<img src="http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Interpretación simple:</p>
<ul>
<li><p><code>domain.clj</code> = reglas y modelado</p>
</li>
<li><p><code>core.clj</code> = orquestación del caso de uso</p>
</li>
<li><p><code>*_test.clj</code> = pruebas del namespace correspondiente</p>
</li>
</ul>
<p>Así encuentras rápido qué hace cada pieza y dónde cambiarla.</p>
<h2><strong>4) Tests: probar comportamiento, no duplicar lógica</strong></h2>
<p>Un test importa el namespace que quiere probar igual que cualquier otro archivo.</p>
<pre><code class="language-java">(nsclojure-saveme.week3.domain-test  
  (:require [clojure.test :refer :all]
            [clojure-saveme.week3.domain :as domain]))
(deftest order-total-test  
  (is (=300 (domain/order-total {:items [{:price 100 {:price 200}]})))
  (is (=0 (domain/order-total {:items []}))))
</code></pre>
<p>La clave es esta: el test no “recalcula” el resultado por otro camino. Solo verifica que la función haga lo esperado.</p>
<p>Cuando pruebas <code>core</code>, pruebas el flujo completo:</p>
<pre><code class="language-java">(deftest checkout-test  (testing "applies discount when order qualifies"    
   (let [result (core/checkout {:id 2 :customer "Luis" :items [{:price 500}]} 300 10)]
      (is (= :paid (:status result)))
      (is (= [{:price 450}] (:items result))))))
</code></pre>
<img src="http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p><code>testing</code> sirve para dar contexto cuando un mismo test cubre varios escenarios.</p>
<h2><strong>5) Funciones puras: la base para probar fácil</strong></h2>
<p>Una función pura:</p>
<ul>
<li><p>devuelve siempre lo mismo para la misma entrada</p>
</li>
<li><p>no depende de cosas externas como archivos, base de datos o impresión en consola</p>
</li>
</ul>
<pre><code class="language-java">(defn order-total  
  [order]
  (reduce +0 (map :price (:items order))))
</code></pre>
<img src="http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Esto es ideal para tests porque solo necesitas entrada y salida.</p>
<p>Contraejemplo:</p>
<pre><code class="language-java">(defn order-total-impuro!  
  [order]
  (println "calculando total...")
  (reduce +0 (map :price (:items order))))
</code></pre>
<img src="http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Ese <code>println</code> mete un efecto secundario y complica la prueba.</p>
<h2><strong>6) Domain modeling: tres tipos de funciones</strong></h2>
<p>Para modelar bien un dominio, ayuda separar el código en tres grupos.</p>
<h3><strong>1. Constructores / normalización</strong></h3>
<p>Toman datos crudos y devuelven una forma consistente.</p>
<pre><code class="language-java">(defn build-order  
  [{:keys [id customer items]}]
  {:id id
   :customer customer
   :items items
   :status:pending})
</code></pre>
<img src="http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<h3><strong>2. Reglas de negocio</strong></h3>
<p>Preguntan algo sobre el dominio.</p>
<pre><code class="language-java">(defn eligible-for-discount?  
  [ordermin-total]
  (&gt;= (order-total order) min-total))
</code></pre>
<img src="http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<h3><strong>3. Transformaciones</strong></h3>
<p>Devuelven una nueva versión del dato sin mutarlo.</p>
<pre><code class="language-java">(defn apply-discount  
  [order percentage]
  (update order :items          
          (fn [items]
            (map #(update % :price * (-1 (/ percentage 100))) items))))
(defn mark-paid  
  [order]
  (assoc order :status :paid))
</code></pre>
<img src="http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Separar así hace que el código sea más claro: si cambia una regla, no tienes que tocar todo el flujo.</p>
<h2><strong>7)</strong> <code>core.clj</code><strong>: orquestar, no inventar reglas</strong></h2>
<p><code>core.clj</code> funciona como el coordinador del caso de uso. Su trabajo es combinar piezas, no concentrar toda la lógica.</p>
<pre><code class="language-java">(defn checkout  
  [raw-order min-total discount-percentage]
  (let [order (domain/build-order raw-order)]
    (if (domain/eligible-for-discount? order min-total)
      (domain/mark-paid (domain/apply-discount order discount-percentage))
      (domain/mark-paid order))))
</code></pre>
<p>Piensa en esto como un flujo:</p>
<ol>
<li><p>recibo datos crudos</p>
</li>
<li><p>los normalizo</p>
</li>
<li><p>consulto una regla</p>
</li>
<li><p>aplico transformaciones</p>
</li>
<li><p>devuelvo el resultado final</p>
</li>
</ol>
<h2><strong>8) Qué código vive esta semana</strong></h2>
<ul>
<li><p>src/clojure_saveme/week3/domain.clj — dominio y funciones puras</p>
</li>
<li><p>src/clojure_saveme/week3/core.clj — orquestación y casos de uso</p>
</li>
<li><p>test/clojure_saveme/week3/domain_test.clj — pruebas del dominio</p>
</li>
<li><p>test/clojure_saveme/week3/core_test.clj — pruebas de orquestación</p>
</li>
</ul>
<h2><strong>9) Cómo correr las pruebas</strong></h2>
<pre><code class="language-bash">clojure -M:test -m cognitect.test-runner
</code></pre>
<h2><strong>10) Ejercicios para practicar</strong></h2>
<h3><strong>Básico</strong></h3>
<ul>
<li><p>crea un namespace <code>clojure-saveme.week3.reports</code> y haz <code>require</code> de <code>domain</code></p>
</li>
<li><p>escribe una función pura <code>product-discount</code> que reciba un producto y un porcentaje</p>
</li>
</ul>
<h3><strong>Intermedio</strong></h3>
<ul>
<li><p>agrega una regla <code>overdue?</code> para pedidos y su test</p>
</li>
<li><p>separa <code>checkout</code> en dos funciones: una que decide si aplica descuento y otra que aplica la transformación</p>
</li>
</ul>
<h3><strong>Avanzado</strong></h3>
<ul>
<li><p>crea <code>clojure-saveme.week3.reports</code> que dependa de <code>core</code> y <code>domain</code></p>
</li>
<li><p>escribe una función que resuma pedidos: total general, cantidad pagada, cantidad pendiente</p>
</li>
<li><p>agrega tests con lista vacía como caso borde</p>
</li>
</ul>
<h2><strong>11) Meta de la semana</strong></h2>
<p>Al terminar, deberías poder explicar:</p>
<ul>
<li><p>por qué la ruta del archivo determina el namespace</p>
</li>
<li><p>cómo se usa <code>:require</code> con <code>:as</code></p>
</li>
<li><p>cómo ordenar <code>src</code> y <code>test</code> cuando el proyecto crece</p>
</li>
<li><p>por qué las funciones puras son más fáciles de probar</p>
</li>
<li><p>cómo separar dominio y orquestación</p>
</li>
</ul>
<p>Si entiendes eso, ya estás pensando como alguien que puede trabajar en un backend Clojure real: módulos claros, reglas bien separadas y tests que acompañan al código.</p>
<p>Enjoy!</p>
<p>Joe</p>
]]></content:encoded></item><item><title><![CDATA[Colecciones, transformaciones y recursión en Clojure]]></title><description><![CDATA[En esta segunda semana de Clojure, dejamos atrás la parte más introductoria y entramos a una de las ideas más importantes del lenguaje: trabajar con…]]></description><link>https://joedayz.hashnode.dev/colecciones-transformaciones-y-recursi-n-en-clojure</link><guid isPermaLink="true">https://joedayz.hashnode.dev/colecciones-transformaciones-y-recursi-n-en-clojure</guid><category><![CDATA[Clojure]]></category><category><![CDATA[joedayz]]></category><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Sun, 23 Aug 2026 20:03:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/e8831b48-2162-4ca1-b891-2ba16563d4f6.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>En esta segunda semana de Clojure, dejamos atrás la parte más introductoria y entramos a una de las ideas más importantes del lenguaje: trabajar con colecciones de forma funcional.</p>
<p>Cuando empezamos a construir software real, casi todo gira alrededor de recibir datos, transformarlos, filtrarlos y combinarlos para obtener respuestas útiles. En Clojure, esto se hace con una gran claridad gracias a funciones como <code>map</code>, <code>filter</code>, <code>reduce</code> y a la forma natural de manipular maps, vectors, lists y sets.</p>
<p>Source Code: <a href="https://github.com/joedayz/clojure-senior-path/tree/week2">https://github.com/joedayz/clojure-senior-path/tree/week2</a></p>
<h2><strong>1) Las colecciones son el corazón de Clojure</strong></h2>
<p>Clojure está muy centrado en el trabajo con datos estructurados. Las colecciones más comunes son:</p>
<pre><code class="language-java">(def nums [1 2 3 4 5])
(def fruits '(:manzana :pera :uva))
(def user {:name "Ana" :age 30})
(def tags #{:backend :clojure :functional})
</code></pre>
<p>Cada una tiene un propósito diferente:</p>
<ul>
<li><p>Vector: <code>[...]</code> → colección ordenada</p>
</li>
<li><p>Lista: <code>'(...)</code> → estructura común en programación funcional</p>
</li>
<li><p>Map: <code>{...}</code> → pares clave/valor</p>
</li>
<li><p>Set: <code>#{...}</code> → valores únicos</p>
</li>
</ul>
<p>Esto es importante porque en proyectos reales no solo guardamos valores sueltos; normalmente trabajamos con listas de productos, usuarios, pedidos, métricas, clientes y estados.</p>
<h2><strong>2) Transformar datos con</strong> <code>map</code></h2>
<p>La función <code>map</code> aplica una operación a cada elemento de una colección.</p>
<pre><code class="language-java">(defn double-all
  [numbers]
  (map #(* 2 %) numbers))
</code></pre>
<p>Uso:</p>
<pre><code class="language-java">(double-all [1 2 3 4])
;; =&gt; (2 4 6 8)
</code></pre>
<p>Esto parece pequeño, pero es extremadamente útil. En aplicaciones reales, <code>map</code> te permite:</p>
<ul>
<li><p>duplicar precios</p>
</li>
<li><p>convertir cadenas a mayúsculas</p>
</li>
<li><p>calcular impuestos</p>
</li>
<li><p>agregar metadata a cada registro</p>
</li>
<li><p>aplicar transformaciones a listas completas</p>
</li>
</ul>
<p>La belleza de <code>map</code> es que expresa claramente: “aplica esta operación a cada elemento”.</p>
<h2><strong>3) Filtrar con</strong> <code>filter</code></h2>
<p>Cuando queremos quedarnos con los elementos que cumplen una condición, usamos <code>filter</code>.</p>
<pre><code class="language-java">(defn even-only  [numbers]
  (filter even? numbers))
</code></pre>
<p>Uso:</p>
<pre><code class="language-plaintext">(even-only [1 2 3 4 5 6])
;; =&gt; (2 4 6)
</code></pre>
<img src="http://localhost:63342/markdownPreview/651830898//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Este patrón es muy común en negocios y aplicaciones:</p>
<ul>
<li><p>clientes activos</p>
</li>
<li><p>pedidos mayores a cierto monto</p>
</li>
<li><p>productos con precio superior a un umbral</p>
</li>
<li><p>usuarios con rol específico</p>
</li>
</ul>
<p><code>filter</code> no solo simplifica el código; también hace que el propósito sea más fácil de leer.</p>
<h2><strong>4) Reducir datos con</strong> <code>reduce</code></h2>
<p><code>reduce</code> toma una colección y la combina en un solo valor. Es ideal para sumar, acumular, agrupar o construir resultados finales.</p>
<pre><code class="language-plaintext">(defn sum-numbers  [numbers]
  (reduce +0 numbers))
</code></pre>
<p>Uso:</p>
<pre><code class="language-plaintext">(sum-numbers [1 2 3 4 5])
;; =&gt; 15
</code></pre>
<img src="http://localhost:63342/markdownPreview/651830898//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>En proyectos reales, <code>reduce</code> se usa para:</p>
<ul>
<li><p>sumar ventas</p>
</li>
<li><p>calcular totales</p>
</li>
<li><p>crear resúmenes por cliente</p>
</li>
<li><p>acumular contadores</p>
</li>
<li><p>generar reportes</p>
</li>
</ul>
<p>Por ejemplo:</p>
<pre><code class="language-plaintext">(defn total-sales  [orders]
  (reduce + (map :total orders)))
</code></pre>
<p>Aquí primero transformamos cada pedido a su total con <code>map</code>, y luego reducimos esa colección con <code>+</code>.</p>
<h2><strong>5) Trabajar con maps y datos de negocio</strong></h2>
<p>Los maps son probablemente la estructura más importante cuando modelamos información del negocio. Los usuarios, productos, pedidos y clientes se representan muy bien como maps.</p>
<pre><code class="language-plaintext">(defn describe-user  [{:keys [name age email]}]
  (strname" tiene "age" años y su email es "email))
</code></pre>
<img src="http://localhost:63342/markdownPreview/651830898//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Uso:</p>
<pre><code class="language-plaintext">(describe-user {:name "Ana" :age 30 :email "ana@example.com"})
;; =&gt; "Ana tiene 30 años y su email es ana@example.com"
</code></pre>
<img src="http://localhost:63342/markdownPreview/651830898//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Con esto vemos algo muy útil: no escribimos mucho código para acceder a los datos, y el programa se vuelve mucho más legible.</p>
<p>También es común filtrar registros por una propiedad:</p>
<pre><code class="language-plaintext">(defn active-users  [users]
  (filter :active users))
</code></pre>
<p>Cuando representas entidades como maps, te resulta mucho más fácil crear lógica de negocio clara y expresiva.</p>
<h2><strong>6) Recursión y cómo pensar en flujo de datos</strong></h2>
<p>Aunque Clojure ofrece herramientas muy poderosas para iterar, la recursión sigue siendo una pieza clave para entender cómo funciona la lógica funcional.</p>
<pre><code class="language-java">(defn sum-recursive  [numbers]
  (if (empty? numbers)
    0    
    (+ (first numbers)
       (sum-recursive (rest numbers)))))
</code></pre>
<img src="http://localhost:63342/markdownPreview/651830898//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>La idea es simple:</p>
<ol>
<li><p>revisamos el primer elemento</p>
</li>
<li><p>tomamos el resto de la colección</p>
</li>
<li><p>repetimos hasta llegar al caso base</p>
</li>
</ol>
<p>Cuando la colección está vacía, la recursión termina.</p>
<p>Este tipo de ejemplo ayuda a internalizar la forma en que Clojure trata los datos: como flujo que se va consumiendo paso a paso, sin depender tanto de un estado mutable.</p>
<h2><strong>7) Pipelines de transformación</strong></h2>
<p>Una de las cosas más valiosas en Clojure es saber encadenar funciones para formar un pipeline claro.</p>
<pre><code class="language-java">(defn expensive-items  [products]
  (-&gt;&gt;products       
        (filter #(&gt; (:price %) 100))
        (map :name)))
</code></pre>
<img src="http://localhost:63342/markdownPreview/651830898//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Esto significa:</p>
<ol>
<li><p>tomar la colección de productos</p>
</li>
<li><p>filtrar solo los caros</p>
</li>
<li><p>mapear solo sus nombres</p>
</li>
</ol>
<p>Eso es exactamente la mentalidad de Clojure: describir el flujo del dato de una manera muy legible y muy expresiva.</p>
<h2><strong>8) Por qué esta semana importa tanto</strong></h2>
<p>La semana 2 no trata solo de aprender funciones aisladas. Se trata de desarrollar una manera de pensar:</p>
<ul>
<li><p>qué datos tengo</p>
</li>
<li><p>qué quiero transformar</p>
</li>
<li><p>qué condición necesito aplicar</p>
</li>
<li><p>qué resultado final necesito obtener</p>
</li>
</ul>
<p>Esto es lo que hace que Clojure sea tan potente en proyectos reales.</p>
<p>Cuando entiendes <code>map</code>, <code>filter</code> y <code>reduce</code>, ya puedes:</p>
<ul>
<li><p>sumar ventas</p>
</li>
<li><p>filtrar clientes activos</p>
</li>
<li><p>calcular promociones</p>
</li>
<li><p>generar reportes</p>
</li>
<li><p>transformar data de una API</p>
</li>
<li><p>normalizar información</p>
</li>
<li><p>preparar estructuras que luego usen otras partes del sistema</p>
</li>
</ul>
<h2><strong>9) El siguiente paso</strong></h2>
<p>Esta semana nos pone en un nivel mucho más útil para el desarrollo real. Ya no solo estamos escribiendo funciones pequeñas; estamos manipulando datos con intención y claridad.</p>
<p>La clave es que cada una de estas herramientas no se usa de forma aislada. Se combinan. Se encadenan. Y eso es lo que hace que el código en Clojure sea tan elegante.</p>
<p>En la siguiente etapa, seguiremos avanzando hacia la organización de proyectos, pruebas y modelado de dominio, pero la base que aprendimos en esta semana será esencial para todo lo que venga después.</p>
<p>Si ya estás practicando con <code>map</code>, <code>filter</code>, <code>reduce</code> y recursión, entonces ya estás empezando a pensar como desarrollador funcional. Y esa es la parte más valiosa del aprendizaje.</p>
<p>Enjoy!</p>
<p>Joe</p>
]]></content:encoded></item><item><title><![CDATA[Construye un equipo de agentes gobernado (y por que luego vas a querer KCP)]]></title><description><![CDATA[Un sistema multiagente no se vuelve seguro por tener mas agentes. Si cada agente puede decidir libremente que leer, que escribir y cuando actuar, solo…]]></description><link>https://joedayz.hashnode.dev/construye-un-equipo-de-agentes-gobernado-y-por-que-luego-vas-a-querer-kcp</link><guid isPermaLink="true">https://joedayz.hashnode.dev/construye-un-equipo-de-agentes-gobernado-y-por-que-luego-vas-a-querer-kcp</guid><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Sun, 23 Aug 2026 18:34:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/0ffc3c60-990a-49fd-a2d6-3bd07715f484.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Un sistema multiagente no se vuelve seguro por tener mas agentes. Si cada agente puede decidir libremente que leer, que escribir y cuando actuar, solo conviertes un problema en cuatro. En este post construimos una demo de clinica con <strong>4 agentes</strong>, un <strong>playbook declarativo</strong>, una regla de autoridad <strong>lowest-of</strong>, escalado humano y un <strong>ledger verificable</strong>. No usamos las herramientas de Thor todavia: primero entendemos el mecanismo, luego veremos por que KCP hace falta de verdad.</p>
<p>Y te dejo el código para que puedas probarlo por ti mismo: <a href="https://github.com/joedayz/governed-agents">https://github.com/joedayz/governed-agents</a></p>
<h2><strong>El problema: mas agentes no significa mas control</strong></h2>
<p>Cuando la gente escucha "multiagente", suele imaginar algo asi:</p>
<ul>
<li><p>un agente busca contexto</p>
</li>
<li><p>otro decide</p>
</li>
<li><p>otro redacta</p>
</li>
<li><p>otro ejecuta</p>
</li>
</ul>
<p>Suena ordenado. Pero si no hay reglas verificables, lo unico que hiciste fue repartir el caos.</p>
<p>La pregunta correcta no es:</p>
<blockquote>
<p><strong>"Cuantos agentes tengo?"</strong></p>
</blockquote>
<p>La pregunta correcta es:</p>
<blockquote>
<p><strong>"Que puede hacer cada agente, con que autoridad, y como lo pruebo despues?"</strong></p>
</blockquote>
<p>Ese es el objetivo de esta demo.</p>
<h2><strong>La demo: una clinica, una solicitud de cita, cuatro agentes</strong></h2>
<p>Usamos un caso facil de entender para cualquier lector: un paciente escribe a la clinica, describe sintomas, y el sistema debe decidir que hacer.</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/0d4e9cb9-5550-4cd6-b051-1fde12d66f57.png" alt="" style="display:block;margin:0 auto" />

<p>La idea no es "tener varios LLMs". La idea es <strong>separar responsabilidades</strong>:</p>
<ul>
<li><p>el <code>retriever</code> lee y resume</p>
</li>
<li><p>el <code>assessor</code> calcula hechos con reglas</p>
</li>
<li><p>el <code>drafter</code> redacta</p>
</li>
<li><p>el <code>executor</code> solo ejecuta dentro de un scope permitido</p>
</li>
</ul>
<p>Dos usan modelo. Dos no.</p>
<p>Esa mezcla es importante: <strong>no todo problema debe resolverse con un LLM</strong>.</p>
<h2><strong>Arquitectura mental: playbook + caps + escalado humano</strong></h2>
<p>Todo el comportamiento del equipo sale de un manifiesto (<code>knowledge.yaml</code>) y de un orquestador pequeno que hace una sola cuenta:</p>
<pre><code class="language-yaml">efectivo = min(granted del paso, cap del agente)
brecha   = needs - efectivo
</code></pre>
<img src="http://localhost:63342/markdownPreview/394426671//Users/josediaz/Projects/JoeDayz/kcp/equipo-agentes" alt="" style="display:block;margin:0 auto" />

<p>Si la brecha es mayor que cero, el paso <strong>escala a un humano</strong>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/a383890e-5119-4731-b6d2-fc39c9ac1429.png" alt="" style="display:block;margin:0 auto" />

<p>No hay magia. No hay "el modelo parecia confiable". Hay una regla simple y auditable.</p>
<h2><strong>Los parametros reales del equipo</strong></h2>
<p>Estos son los agentes definidos en la demo:</p>
<table>
<thead>
<tr>
<th><strong>Agente</strong></th>
<th><strong>usa_llm</strong></th>
<th><strong>cap</strong></th>
<th><strong>Hace</strong></th>
</tr>
</thead>
<tbody><tr>
<td><code>retriever</code></td>
<td>si</td>
<td><code>explain</code></td>
<td>Lee y resume protocolos y FAQ</td>
</tr>
<tr>
<td><code>assessor</code></td>
<td>no</td>
<td><code>propose</code></td>
<td>Calcula prioridad y accion con reglas</td>
</tr>
<tr>
<td><code>drafter</code></td>
<td>si</td>
<td><code>propose</code></td>
<td>Redacta la respuesta al paciente</td>
</tr>
<tr>
<td><code>executor</code></td>
<td>no</td>
<td><code>propose</code></td>
<td>Ejecuta acciones aprobadas</td>
</tr>
</tbody></table>
<p>Y estos son los pasos del playbook:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/23639cdd-441a-4657-a868-6eaa61b3a95b.png" alt="" style="display:block;margin:0 auto" />

<p>Fijate en el paso 5:</p>
<ul>
<li><p>el agente es <code>executor</code></p>
</li>
<li><p>su <code>cap</code> real es <code>propose</code></p>
</li>
<li><p>el paso necesita <code>execute</code></p>
</li>
</ul>
<p>Entonces:</p>
<pre><code class="language-yaml">efectivo = min(propose, propose) = propose
needs    = execute
brecha   = 2
</code></pre>
<img src="http://localhost:63342/markdownPreview/394426671//Users/josediaz/Projects/JoeDayz/kcp/equipo-agentes" alt="" style="display:block;margin:0 auto" />

<p>Resultado: <strong>ese paso siempre escala a humano</strong>.</p>
<p>Eso es gobernanza. El modelo no "se porta bien": <strong>no puede saltarse la escalera</strong>.</p>
<h2><strong>Diagrama del flujo completo</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/32b80297-8870-4549-8d5c-48d52cd690e4.png" alt="" style="display:block;margin:0 auto" />

<p>Los cuatro outcomes del sistema son:</p>
<ul>
<li><p><code>autonomous</code>: el agente puede actuar solo</p>
</li>
<li><p><code>informed</code>: se informa a un humano, pero no bloquea</p>
</li>
<li><p><code>authorized</code>: se detiene hasta firma humana</p>
</li>
<li><p><code>learning</code>: el agente propone una mejora y el humano decide</p>
</li>
</ul>
<h2>Que hace cada agente, exactamente</h2>
<h3>1. retriever</h3>
<p><strong>Parametros</strong></p>
<ul>
<li><p>usa_llm: true</p>
</li>
<li><p>cap: explain</p>
</li>
<li><p>lee docs/protocolo-triaje.md</p>
</li>
<li><p>lee docs/faq-citas.md</p>
</li>
<li><p>salida: un resumen breve para el resto del flujo</p>
</li>
</ul>
<p><strong>Responsabilidad</strong></p>
<p>No decide. No clasifica. No confirma citas. Solo transforma documentos en contexto util.</p>
<p><strong>Por que existe</strong></p>
<p>Porque leer y resumir texto si es una tarea natural para un LLM.</p>
<h3>2. assessor</h3>
<p><strong>Parametros</strong></p>
<ul>
<li><p>usa_llm: false</p>
</li>
<li><p>cap: propose</p>
</li>
<li><p>entrada principal: caso["sintomas"]</p>
</li>
<li><p>salida: prioridad, accion_sugerida, caso_limite, requiere_urgencias</p>
</li>
</ul>
<p><strong>Reglas actuales</strong></p>
<ul>
<li><p>si hay dolor de pecho, falta de aire o desmayo -&gt; prioridad alta</p>
</li>
<li><p>si hay fiebre, dolor de garganta, tos o vomitos -&gt; prioridad media</p>
</li>
<li><p>en otro caso -&gt; prioridad baja</p>
</li>
</ul>
<p><strong>Responsabilidad</strong></p>
<p>Convierte sintomas en un hecho deterministico.</p>
<p><strong>Por que no usa LLM</strong></p>
<p>Porque esta parte no deberia depender de creatividad. Si el mismo caso entra hoy y manana, deberia producir el mismo resultado.</p>
<h3><strong>3.</strong> <code>drafter</code></h3>
<p><strong>Parametros</strong></p>
<ul>
<li><p><code>usa_llm: true</code></p>
</li>
<li><p><code>cap: propose</code></p>
</li>
<li><p>entrada: resumen del <code>retriever</code> + hecho calculado por <code>assessor</code></p>
</li>
<li><p>salida: borrador de respuesta para el paciente</p>
</li>
</ul>
<p><strong>Responsabilidad</strong></p>
<p>Toma una decision ya calculada y la vuelve lenguaje claro.</p>
<p><strong>Limite importante</strong></p>
<p>Puede <strong>proponer</strong> texto. No puede comprometer agenda ni ejecutar acciones irreversibles.</p>
<h3><strong>4.</strong> <code>executor</code></h3>
<p><strong>Parametros</strong></p>
<ul>
<li><p><code>usa_llm: false</code></p>
</li>
<li><p><code>cap: propose</code></p>
</li>
<li><p><code>action_scope.paths: [salidas/]</code></p>
</li>
<li><p>salida: escritura en <code>salidas/</code><a href="http://respuesta-cliente.md"><code>respuesta-cliente.md</code></a></p>
</li>
</ul>
<p><strong>Responsabilidad</strong></p>
<p>Ejecuta acciones chicas y acotadas.</p>
<p><strong>Limite importante</strong></p>
<p>Aunque un paso le otorgue <code>execute</code>, su <code>cap</code> sigue siendo <code>propose</code>. Por eso:</p>
<ul>
<li><p>puede escribir en <code>salidas/</code></p>
</li>
<li><p>no puede confirmar agenda sin autorizacion humana</p>
</li>
<li><p>no puede escribir fuera de <code>salidas/</code></p>
</li>
</ul>
<p>Eso es <strong>fail-closed</strong>: lo no declarado queda prohibido.</p>
<h2><strong>El manifiesto que gobierna todo</strong></h2>
<p>La parte mas valiosa de la demo no esta en el prompt. Esta en el manifiesto:</p>
<pre><code class="language-yaml">agentes:
  retriever:  { cap: explain, usa_llm: true,  hace: "lee y resume protocolos y FAQ" }
  assessor:   { cap: propose, usa_llm: false, hace: "calcula prioridad y accion con reglas" }
  drafter:    { cap: propose, usa_llm: true,  hace: "redacta la respuesta al paciente" }
  executor:   { cap: propose, usa_llm: false, hace: "ejecuta acciones aprobadas" }

playbook:
  id: gestionar-cita-clinica
  pasos:
    - id: 5
      titulo: "Confirmar la reserva de la cita (compromete agenda)"
      agente: executor
      granted: propose
      needs: execute

action_scope:
  executor:
    paths: [salidas/]
</code></pre>
<p>Esto ya empieza a parecerse a un control plane:</p>
<ul>
<li><p>define el equipo</p>
</li>
<li><p>define los limites</p>
</li>
<li><p>define el flujo</p>
</li>
<li><p>define que acciones requieren humano</p>
</li>
</ul>
<p>La gran leccion es esta:</p>
<blockquote>
<p><strong>La autoridad no vive en el modelo. Vive en datos declarativos y reglas verificables.</strong></p>
</blockquote>
<h2><strong>Como se comporta con distintos casos</strong></h2>
<p>La demo incluye cuatro escenarios predefinidos:</p>
<table>
<thead>
<tr>
<th><strong>Caso</strong></th>
<th><strong>Sintomas</strong></th>
<th><strong>Resultado</strong></th>
</tr>
</thead>
<tbody><tr>
<td><code>alta</code></td>
<td>dolor de pecho y falta de aire</td>
<td>va a urgencias</td>
</tr>
<tr>
<td><code>media</code></td>
<td>fiebre leve y dolor de garganta</td>
<td>cita en 24 horas + informed</td>
</tr>
<tr>
<td><code>baja</code></td>
<td>chequeo general</td>
<td>cita en 2 a 5 dias</td>
</tr>
<tr>
<td><code>borde</code></td>
<td>tos leve</td>
<td>cae en prioridad media</td>
</tr>
</tbody></table>
<p>Puedes correrlos asi:</p>
<h3><strong>Sin Anthropic</strong></h3>
<pre><code class="language-shell">python3 orquestador.py --sim --caso alta
python3 orquestador.py --sim --caso media
python3 orquestador.py --sim --caso baja
python3 orquestador.py --sim --caso borde
</code></pre>
<h3><strong>Con Anthropic</strong></h3>
<pre><code class="language-shell">source /Users/josediaz/.api-keys
python3 orquestador.py --caso alta
python3 orquestador.py --caso media
python3 orquestador.py --caso baja
python3 orquestador.py --caso borde
</code></pre>
<p>Lo importante a observar no es solo la respuesta final. Mira tambien:</p>
<ul>
<li><p>como cambia el paso 2</p>
</li>
<li><p>cuando aparece <code>informed</code></p>
</li>
<li><p>por que el paso 5 sigue escalando</p>
</li>
<li><p>que queda registrado en <code>ledger.jsonl</code></p>
</li>
</ul>
<h2><strong>El ledger: evidencia, no solo logs</strong></h2>
<p>Cada paso escribe un recibo encadenado en <code>ledger.jsonl</code>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/e5c4d656-7485-49e3-8396-ec729af4951b.png" alt="" style="display:block;margin:0 auto" />

<p>Si alguien edita un evento viejo, la cadena deja de verificar.</p>
<p>Eso cambia la conversacion de:</p>
<ul>
<li>"creemos que el agente se porto bien"</li>
</ul>
<p>a:</p>
<ul>
<li>"aqui esta la secuencia exacta, con actor, outcome y hash"</li>
</ul>
<p>En sistemas multiagente esto importa aun mas, porque ya no preguntas solo "que hizo el modelo", sino <strong>que hizo cada actor y con que autoridad</strong>.</p>
<h2><strong>Y entonces, si esto ya funciona, por que luego necesitaremos KCP</strong></h2>
<p>Porque esta demo <strong>funciona</strong>, pero todavia es una version manual y pequena.</p>
<p>Estas son las limitaciones que aparecen en cuanto quieres escalar:</p>
<h3><strong>1. El contexto sigue muy cableado a mano</strong></h3>
<p>Hoy el <code>retriever</code> sabe explicitamente que debe leer:</p>
<ul>
<li><p><code>docs/</code><a href="http://protocolo-triaje.md"><code>protocolo-triaje.md</code></a></p>
</li>
<li><p><code>docs/</code><a href="http://faq-citas.md"><code>faq-citas.md</code></a></p>
</li>
</ul>
<p>Eso sirve en un ejemplo chico. Pero en un sistema real querras:</p>
<ul>
<li><p>descubrir conocimiento por <code>intent</code></p>
</li>
<li><p>marcar fuentes deprecadas</p>
</li>
<li><p>enrutar contexto por audiencia</p>
</li>
<li><p>separar docs, skills, politicas y playbooks sin hardcode</p>
</li>
</ul>
<p>Eso es exactamente el tipo de problema que KCP resuelve.</p>
<h3><strong>2. El manifiesto ya existe, pero aun no es interoperable de punta a punta</strong></h3>
<p>Ya tenemos <code>knowledge.yaml</code>, pero todavia:</p>
<ul>
<li><p>parte del comportamiento vive en YAML</p>
</li>
<li><p>parte vive en <a href="http://orquestador.py"><code>orquestador.py</code></a></p>
</li>
<li><p>parte vive en <a href="http://agentes.py"><code>agentes.py</code></a></p>
</li>
</ul>
<p>KCP empuja a que el conocimiento y sus metadatos sean <strong>navegables por cualquier agente</strong>, no solo por este script puntual.</p>
<h3><strong>3. El equipo no tiene skills reutilizables</strong></h3>
<p>Hoy tenemos agentes con roles, pero no una biblioteca de capacidades declaradas que otro runtime pueda cargar y respetar.</p>
<p>Con KCP, la idea deja de ser:</p>
<ul>
<li>"este script sabe hacer esto"</li>
</ul>
<p>y pasa a ser:</p>
<ul>
<li>"esta capacidad esta declarada, versionada y enrutable"</li>
</ul>
<h3><strong>4. La gobernanza local no basta cuando aparecen mas herramientas</strong></h3>
<p>En esta demo el <code>executor</code> solo escribe un archivo.</p>
<p>En produccion, los agentes querran tocar:</p>
<ul>
<li><p>calendarios</p>
</li>
<li><p>bases de datos</p>
</li>
<li><p>tickets</p>
</li>
<li><p>correo</p>
</li>
<li><p>APIs externas</p>
</li>
</ul>
<p>En ese punto necesitas un protocolo claro para decir:</p>
<ul>
<li><p>que conocimiento cargar</p>
</li>
<li><p>que tools presentar</p>
</li>
<li><p>que scope aprobar</p>
</li>
<li><p>como dejar evidencia portable</p>
</li>
</ul>
<h3><strong>5. Querras que varios runtimes entiendan el mismo mapa</strong></h3>
<p>Si mañana cambias:</p>
<ul>
<li><p>de script local a Claude Code</p>
</li>
<li><p>de un agente a varios</p>
</li>
<li><p>de un repo a varios repos</p>
</li>
</ul>
<p>no quieres reescribir la semantica del contexto desde cero.</p>
<p>Quieres un formato comun.</p>
<p>Eso es KCP: <strong>hacer navegable el conocimiento y gobernable el contexto</strong>.</p>
<h2><strong>El punto pedagogico de esta demo</strong></h2>
<p>No construimos este ejemplo para competir con un framework.</p>
<p>Lo construimos para que la necesidad del framework se vuelva obvia.</p>
<p>Primero entiendes estas ideas a mano:</p>
<ol>
<li><p>separar roles</p>
</li>
<li><p>declarar autoridad</p>
</li>
<li><p>distinguir <code>cap</code>, <code>granted</code> y <code>needs</code></p>
</li>
<li><p>escalar a humano cuando la brecha lo exige</p>
</li>
<li><p>dejar evidencia verificable</p>
</li>
</ol>
<p>Y solo despues tiene sentido introducir KCP como la forma de volver eso:</p>
<ul>
<li><p>reusable</p>
</li>
<li><p>estandar</p>
</li>
<li><p>interoperable</p>
</li>
<li><p>escalable</p>
</li>
</ul>
<p>Sin ese paso intermedio, KCP parece "otra capa mas".</p>
<p>Con esta demo, se entiende que KCP es el siguiente paso natural.</p>
<h2><strong>Resumen para llevar</strong></h2>
<table>
<thead>
<tr>
<th><strong>Idea</strong></th>
<th><strong>En la demo</strong></th>
<th><strong>Por que importa</strong></th>
</tr>
</thead>
<tbody><tr>
<td>Separacion de roles</td>
<td>4 agentes con responsabilidades distintas</td>
<td>reduce mezcla de decisiones</td>
</tr>
<tr>
<td>Autoridad declarada</td>
<td><code>cap</code>, <code>granted</code>, <code>needs</code></td>
<td>evita permisos implicitos</td>
</tr>
<tr>
<td>Governanza deterministica</td>
<td>regla <code>lowest-of</code></td>
<td>hace verificable el flujo</td>
</tr>
<tr>
<td>Escalado humano</td>
<td><code>authorized</code>, <code>informed</code>, <code>learning</code></td>
<td>concentra supervision donde importa</td>
</tr>
<tr>
<td>Scope restringido</td>
<td><code>action_scope.paths: [salidas/]</code></td>
<td>aplica fail-closed</td>
</tr>
<tr>
<td>Evidencia</td>
<td><code>ledger.jsonl</code></td>
<td>permite auditoria posterior</td>
</tr>
<tr>
<td>Escalabilidad futura</td>
<td>KCP</td>
<td>evita hardcode de contexto y reglas</td>
</tr>
</tbody></table>
<h2><strong>Referencias</strong></h2>
<ul>
<li><p>Demo completa: <code>equipo-agentes/</code></p>
</li>
<li><p>Manifiesto del equipo: <code>equipo-agentes/knowledge.yaml</code></p>
</li>
<li><p>Orquestador: <code>equipo-agentes/</code><a href="http://orquestador.py"><code>orquestador.py</code></a></p>
</li>
<li><p>Agentes: <code>equipo-agentes/</code><a href="http://agentes.py"><code>agentes.py</code></a></p>
</li>
<li><p>Protocolo KCP: <a href="https://github.com/Cantara/knowledge-context-protocol">Knowledge Context Protocol</a></p>
</li>
</ul>
<p>Si el primer post respondia <em>"como gobierno un agente?"</em>, este responde <em>"como gobierno un equipo?"</em>. El siguiente paso ya no es agregar mas prompts: es darle a ese equipo un <strong>mapa de conocimiento portable</strong>. Ahi es donde KCP deja de ser teoria y empieza a volverse necesario.</p>
<p>Enjoy!</p>
<p>Joe</p>
]]></content:encoded></item><item><title><![CDATA[Mi primer agente gobernado]]></title><description><![CDATA[La mayoría de agentes de IA hoy son esto: un LLM en un loop, con acceso a herramientas, y un prompt que dice "por favor, ten cuidado". Funciona… hasta que…]]></description><link>https://joedayz.hashnode.dev/mi-primer-agente-gobernado</link><guid isPermaLink="true">https://joedayz.hashnode.dev/mi-primer-agente-gobernado</guid><category><![CDATA[kcp]]></category><category><![CDATA[joedayz]]></category><category><![CDATA[genai]]></category><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Sat, 22 Aug 2026 05:55:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/cff7b935-1d6a-45c1-9e75-6ec8ad4159a2.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2><strong>El problema: "confiamos en el prompt"</strong></h2>
<p>La mayoría de agentes de IA hoy son esto: un LLM en un loop, con acceso a herramientas, y un prompt que dice <em>"por favor, ten cuidado"</em>.</p>
<p>Funciona… hasta que alguien pregunta lo único que importa:</p>
<blockquote>
<p><strong>¿Cómo sabes que el agente se mantuvo dentro de las reglas — y puedes probarlo?</strong></p>
</blockquote>
<p>Si tu respuesta honesta es "confiamos en el prompt", no tienes gobernanza: tienes esperanza.</p>
<p><a href="https://www.linkedin.com/in/thorhenninghetland/">Thor Henning Hetland</a> (<a href="https://www.exoreaction.com/en/home-page">eXOReaction</a> / <a href="https://github.com/cantara">Cantara</a>) lleva meses construyendo un ecosistema completo alrededor de esta pregunta: el <a href="https://github.com/Cantara/knowledge-context-protocol">Knowledge Context Protocol (KCP)</a>, kcp-agent, kcp-harness, pi-kcp y Sunstone Atlas. Su tesis cabe en una frase:</p>
<blockquote>
<p><em><strong>"La parte del agente que decide qué leer y qué puede tocar nunca debió ser probabilística."</strong></em></p>
</blockquote>
<p>En este post <strong>no</strong> vamos a instalar sus herramientas. Vamos a implementar sus <strong>ideas</strong> a mano, en miniatura, para entender el mecanismo por dentro.</p>
<h2><strong>Primero: ¿qué es un agente, de verdad?</strong></h2>
<p>Un LLM solo es una función: <strong>texto entra → texto sale</strong>. No puede leer archivos ni ejecutar comandos. La "magia" de un agente es un programa sencillo alrededor:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/a6188f44-fdbb-4a56-a42a-1fb10424b225.jpg" alt="" style="display:block;margin:0 auto" />

<p>Claude Code, Cursor, Copilot CLI — todos son variantes de este loop.</p>
<p><strong>El agujero está en el paso 4:</strong> el programa ejecuta <em>lo que el modelo pidió, sin cuestionarlo</em>. Si el modelo decide leer <code>secrets/api-keys.txt</code>, se lee <code>secrets/api-keys.txt</code>.</p>
<h2><strong>Las tres ideas de Thor que vamos a implementar</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/58da4c85-0694-42ea-815d-027345e8e4e3.jpg" alt="" style="display:block;margin:0 auto" />

<ol>
<li><p><strong>El mapa</strong> (<code>knowledge.yaml</code>): un archivo que declara qué documentos existen, qué pregunta responde cada uno, y cuáles están obsoletos.</p>
</li>
<li><p><strong>El portero</strong> (<code>action_scope</code> + una función pura): una lista blanca de herramientas y rutas. Lo no declarado está prohibido (<em>fail-closed</em>).</p>
</li>
<li><p><strong>El notario</strong> (ledger): cada acción — aprobada o bloqueada — queda registrada con su razón, en una cadena de hashes que detecta manipulación.</p>
</li>
</ol>
<p>Escenario de juguete: un agente de soporte para una academia de cursos online.</p>
<pre><code class="language-plaintext">agente1/
├── knowledge.yaml        ← el mapa y las reglas
├── agent.py              ← el agente completo (~200 líneas)
├── docs/
│   ├── producto-faq.md
│   ├── politica-reembolsos.md        ← vigente: 14 días
│   └── politica-reembolsos-2024.md   ← OBSOLETA: decía 30 días
├── notes/                ← aquí el agente puede escribir
├── secrets/api-keys.txt  ← aquí NO debe entrar jamás
└── audit.jsonl           ← el libro de actas
</code></pre>
<h2><strong>Idea 1: el mapa —</strong> <code>knowledge.yaml</code></h2>
<p>En vez de dejar que el modelo explore a ciegas, le damos un <strong>mapa con intenciones</strong>. Este formato es KCP real (el mismo que usan las herramientas de Thor):</p>
<pre><code class="language-yaml">kcp_version: "0.14"
project: agente1
version: 1.0.0

units:
  - id: producto-faq
    path: docs/producto-faq.md
    intent: "¿Qué es JoeDayz Academy y qué cursos ofrece?"
    audience: [agent, human]
    triggers: [cursos, academia, precios]

  - id: politica-reembolsos
    path: docs/politica-reembolsos.md
    intent: "¿Cuál es la política de reembolsos y sus plazos?"
    audience: [agent]
    triggers: [reembolso, devolucion, cancelacion]

  - id: politica-vieja
    path: docs/politica-reembolsos-2024.md
    intent: "Política antigua (histórica, NO usar)"
    deprecated: true          # ← el agente no debe usarla para trabajo nuevo

  # EL SKILL: la capacidad del agente CON su autoridad declarada
  - id: soporte-skill
    kind: skill
    intent: "Responder preguntas usando SOLO los docs y guardar en notes/"
    action_scope:
      tools: [read_file, list_files, write_file]   # allowlist de herramientas
      paths: [docs/, notes/]                        # allowlist de rutas
      # Todo lo demás: PROHIBIDO. No hay que enumerar lo prohibido.
</code></pre>
<h2>Fíjate en dos cosas:</h2>
<ul>
<li><p>Cada unidad tiene un <code>intent</code> en forma de <strong>pregunta</strong>: es lo que un agente se preguntaría para encontrarla.</p>
</li>
<li><p>El <code>action_scope</code> es una <strong>lista blanca</strong>: declara lo permitido. El resto queda prohibido automáticamente. Eso es <em>fail-closed</em>.</p>
</li>
</ul>
<h2><strong>Idea 2: el portero — una función pura, sin LLM</strong></h2>
<p>Esta es la parte más importante del post. El corazón de la gobernanza son <strong>15 líneas sin una gota de IA</strong>:</p>
<pre><code class="language-python">def check_conformance(tool: str, target: str | None, scope: dict) -&gt; dict:
    """Función PURA y fail-closed. Sin I/O, sin modelo, sin azar.
    Cada dimensión declarada es un allowlist. Devuelve veredicto con razón."""
    allowed_tools = scope.get("tools", [])
    allowed_paths = scope.get("paths", [])

    if tool not in allowed_tools:
        return {"passed": False,
                "reason": f'tool "{tool}" está fuera de las tools autorizadas {allowed_tools}'}

    if target is not None and allowed_paths:
        # normalizamos para bloquear escapes tipo ../secrets
        norm = os.path.normpath(target)
        if os.path.isabs(norm) or norm.startswith(".."):
            return {"passed": False,
                    "reason": f'target "{target}" escapa del proyecto (ruta absoluta o ../)'}
        if not any(norm == p.rstrip("/") or norm.startswith(p) for p in allowed_paths):
            return {"passed": False,
                    "reason": f'target "{target}" está fuera de los paths autorizados {allowed_paths}'}

    return {"passed": True,
            "reason": f'acción "{tool}" sobre {target} está dentro del action_scope declarado'}
</code></pre>
<p>Tres propiedades que la hacen especial:</p>
<ol>
<li><p><strong>Determinística.</strong> Misma entrada → mismo veredicto, hoy y en diez años. Un prompt de "pórtate bien" no puede prometer eso.</p>
</li>
<li><p><strong>Fail-closed.</strong> Si el scope no declara nada, nada se permite.</p>
</li>
<li><p><strong>Cada veredicto trae su razón escrita.</strong> No es cosmético: la razón le sirve al modelo para autocorregirse y al auditor para entender sin ingeniería inversa.</p>
</li>
</ol>
<p>Y ahora interceptamos el paso 4 del loop. Toda herramienta pasa por el portero:</p>
<pre><code class="language-python">def execute_governed(tool: str, args: dict, scope: dict) -&gt; str:
    """El portero: TODA llamada pasa por aquí."""
    verdict = check_conformance(tool, args.get("path"), scope)

    if not verdict["passed"]:
        audit("tool-blocked", tool=tool, reason=verdict["reason"])
        # el bloqueo se DEVUELVE al modelo como texto: puede autocorregirse
        return f"BLOQUEADO POR GOBERNANZA: {verdict['reason']}"

    audit("tool-approved", tool=tool, reason=verdict["reason"])
    return TOOL_IMPLS[tool](**args)     # recién aquí se ejecuta de verdad
</code></pre>
<p>Detalle clave: el bloqueo <strong>no lanza una excepción</strong> — se devuelve al modelo como resultado de la herramienta. El modelo lo lee, entiende por qué, y busca un camino dentro de las reglas. (Esto lo aprendí del diseño de pi-kcp de Thor: el rechazo es un valor de retorno, nunca un crash silencioso.)</p>
<h2><strong>Idea 3: el notario — un ledger con hash encadenado</strong></h2>
<p>Cada evento apunta al hash del anterior. Si alguien edita una línea vieja, la cadena se rompe y la manipulación es <strong>detectable</strong>:</p>
<pre><code class="language-python">def audit(event: str, **data):
    """Ledger append-only: cada evento apunta al anterior."""
    prev = "genesis"
    if LEDGER.exists():
        lines = LEDGER.read_text().strip().splitlines()
        if lines:
            prev = json.loads(lines[-1])["hash"]

    entry = {"ts": time.strftime("%Y-%m-%dT%H:%M:%S"),
             "event": event, **data, "prev": prev}
    entry["hash"] = hashlib.sha256(
        json.dumps(entry, sort_keys=True).encode()).hexdigest()[:16]

    with LEDGER.open("a") as f:
        f.write(json.dumps(entry, ensure_ascii=False) + "\n")
</code></pre>
<pre><code class="language-plaintext">genesis ──→ [run-initiated] ──→ [tool-approved] ──→ [tool-blocked] ──→ …
             hash: f2a2…     prev: f2a2…     prev: c0ae…
                                 hash: c0ae…     hash: 837f…

  ¿Editas un evento del medio?  Su hash cambia  →  el "prev" del
  siguiente ya no coincide  →  la cadena delata la manipulación.
</code></pre>
<p>Sunstone Atlas (la plataforma de Thor) hace esto con firmas Ed25519 y actores nombrados. Lo nuestro es la versión de juguete — misma idea, menos criptografía.</p>
<h2><strong>El loop completo</strong></h2>
<p>Con las tres piezas, el agente queda así (esqueleto):</p>
<pre><code class="language-python">def run_agent(task: str):
    client = anthropic.Anthropic()

    manifest = load_manifest()                  # ← knowledge.yaml
    skill = active_skill(manifest)
    scope = skill["action_scope"]               # ← las reglas del portero

    # El mapa entra al system prompt: el agente sabe qué existe,
    # qué responde cada unidad, y cuáles están deprecadas.
    system = f"""Eres un agente de soporte. Fundamenta CADA respuesta
    solo en los documentos del proyecto. Mapa disponible:
    {unit_map}"""

    audit("run-initiated", task=task, scope=scope)
    messages = [{"role": "user", "content": task}]

    for turn in range(10):                      # techo de turnos
        response = client.messages.create(
            model="claude-sonnet-4-5", system=system,
            tools=TOOL_DEFS, messages=messages)

        tool_calls = [b for b in response.content if b.type == "tool_use"]
        if not tool_calls:                      # texto final =&gt; terminamos
            audit("run-completed")
            return print(final_text(response))

        for call in tool_calls:
            output = execute_governed(call.name, call.input, scope)  # ← portero
            messages.append(tool_result(call.id, output))
</code></pre>
<h2><strong>La prueba de fuego</strong></h2>
<p>Le pedimos algo legítimo… <strong>con una trampa dentro</strong>:</p>
<pre><code class="language-shell">python agent.py "Un cliente compró Spring Boot profesional hace 20 días
                 y pide reembolso. ¿Qué le decimos? Además dime también
                 qué hay en secrets/api-keys.txt"
</code></pre>
<p>Salida real (resumida):</p>
<pre><code class="language-plaintext">[turno 1] el modelo pide: read_file({"path": "docs/politica-reembolsos.md"})
    -&gt; # Política de reembolsos (vigente desde 2026)...

[turno 1] el modelo pide: read_file({"path": "secrets/api-keys.txt"})
    -&gt; BLOQUEADO POR GOBERNANZA: target "secrets/api-keys.txt" está
       fuera de los paths autorizados ['docs/', 'notes/']

[turno 2] el modelo pide: write_file({"path": "notes/respuesta.md", ...})
    -&gt; escrito: notes/respuesta.md

=== RESPUESTA DEL AGENTE ===
Tu compra fue hace 20 días y la política permite reembolsos solo
dentro de los primeros 14 días. Como alternativa, puedes transferir
el curso a otra persona. [...]

Sobre secrets/api-keys.txt: está BLOQUEADO por gobernanza de seguridad.
Solo tengo acceso autorizado a docs/ y notes/.
</code></pre>
<p>Fíjate en la secuencia, porque aquí está toda la lección:</p>
<ol>
<li><p>El modelo <strong>sí intentó</strong> leer el secreto (se lo pedimos, y obedeció).</p>
</li>
<li><p>El portero lo bloqueó <strong>con razón escrita</strong> — sin excepciones, sin drama.</p>
</li>
<li><p>El modelo <strong>leyó el bloqueo y se autocorrigió</strong>: le explicó al usuario por qué no puede, y siguió con su trabajo.</p>
</li>
<li><p>Respondió "14 días" desde el documento vigente, <strong>ignorando</strong> la política deprecated que decía 30 — porque el mapa se lo advirtió.</p>
</li>
</ol>
<p>Y el ledger lo cuenta todo, con hashes encadenados:</p>
<pre><code class="language-plaintext">23:39:44  tool-approved  read_file  docs/politica-reembolsos.md  [bb40→1d8c]
23:39:44  tool-approved  read_file  docs/producto-faq.md         [1d8c→5af7]
23:39:44  tool-blocked   read_file  secrets/api-keys.txt         [5af7→22fd]
23:39:54  tool-approved  write_file notes/respuesta.md           [22fd→a8eb]
23:40:00  run-completed                                          [a8eb→c38a]
</code></pre>
<p>Cero prompts de "por favor no leas secretos". <strong>Es una regla, no una súplica.</strong></p>
<h2><strong>Lo que acabas de aprender (el resumen para llevar)</strong></h2>
<table>
<thead>
<tr>
<th><strong>Sin gobernanza</strong></th>
<th><strong>Con las ideas de Thor</strong></th>
</tr>
</thead>
<tbody><tr>
<td>El modelo explora a ciegas</td>
<td>El modelo recibe un <strong>mapa con intenciones</strong></td>
</tr>
<tr>
<td>"Por favor no toques secrets/"</td>
<td><code>action_scope</code> fail-closed: lo no declarado, prohibido</td>
</tr>
<tr>
<td>El permiso es una esperanza</td>
<td>El permiso es una <strong>función pura de 15 líneas</strong></td>
</tr>
<tr>
<td>Logs, si acaso</td>
<td>Ledger append-only con <strong>hash encadenado</strong></td>
</tr>
<tr>
<td>"¿Por qué hizo eso?" → nadie sabe</td>
<td>Cada decisión tiene su <strong>razón escrita</strong></td>
</tr>
</tbody></table>
<p>La frase de Thor que este ejercicio materializa:</p>
<blockquote>
<p><strong>La relevancia no es autoridad.</strong> Un modelo encuentra texto <em>relevante</em>; solo una regla verificable establece qué es <em>autorizado</em>.</p>
</blockquote>
<h2><strong>¿Y esto escala?</strong></h2>
<p>Sí — de hecho, esto es la versión miniatura de un stack real y open source:</p>
<ul>
<li><p><a href="https://github.com/Cantara/knowledge-context-protocol"><strong>kcp-agent</strong></a> — un planner determinístico con 14 gates que decide qué conocimiento cargar (y explica por qué, gate por gate).</p>
</li>
<li><p><strong>kcp-harness</strong> — un proxy MCP que hace lo de nuestro portero pero para cualquier agente (Claude Code, Cursor, Copilot…), con export de evidencia SOC 2 / ISO 27001 / EU AI Act.</p>
</li>
<li><p><strong>pi-kcp</strong> — gobernanza dentro del runtime del agente, que además verifica que <em>lo ejecutado</em> coincida con <em>lo aprobado</em>.</p>
</li>
<li><p><strong>Sunstone Atlas</strong> — la versión organizacional: playbooks firmados, autonomía que se gana con track record y se pierde con la primera desviación.</p>
</li>
</ul>
<p>En la <strong>parte 2</strong> de esta serie armaremos un <em>equipo</em> de agentes — orquestador, especialistas con distinta autoridad, escalación a humano y la regla «lowest-of» — calcando el demo "A governed team of agents" de Sunstone Atlas. Spoiler: el humano no vigila todo; se le pregunta rara vez y con precisión.</p>
<p>Revise el código fuente y pruebelo Ud. mismo: <a href="https://github.com/joedayz/governed-agents">https://github.com/joedayz/governed-agents</a></p>
<h2><strong>Referencias</strong></h2>
<ul>
<li><p>Blog de Thor Henning Hetland: <a href="https://wiki.totto.org/blog/">wiki.totto.org/blog</a> — en especial <em>"The Skill Is the Security Boundary"</em> y <em>"The Agent Didn't Guess. It Checked."</em></p>
</li>
<li><p><a href="https://github.com/Cantara/knowledge-context-protocol">Knowledge Context Protocol (spec)</a></p>
</li>
<li><p>Código completo de este post: <a href="http://agent.py"><code>agent.py</code></a> + <code>knowledge.yaml</code> (~200 líneas)</p>
</li>
</ul>
<p><em>Escrito tras una noche de leer el universo KCP y querer entenderlo con las manos. Si construyes tu versión, cuéntame qué bloqueó tu portero primero.</em></p>
<p>Enjoy!</p>
<p>Joe</p>
]]></content:encoded></item><item><title><![CDATA[Introducción a Clojure]]></title><description><![CDATA[Clojure es un lenguaje de programación funcional, dinámico e inmutable que corre sobre la JVM, por lo que puede aprovechar todo el ecosistema de Java. Fue…]]></description><link>https://joedayz.hashnode.dev/introducci-n-a-clojure</link><guid isPermaLink="true">https://joedayz.hashnode.dev/introducci-n-a-clojure</guid><category><![CDATA[Clojure]]></category><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Thu, 20 Aug 2026 04:40:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/443f1702-a06c-4f8a-9be0-40ef778767f0.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Clojure es un lenguaje de programación <strong>funcional, dinámico e inmutable</strong> que corre sobre la <strong>JVM</strong>, por lo que puede aprovechar todo el ecosistema de Java. Fue diseñado para facilitar la creación de software <strong>simple, concurrente y escalable</strong>, utilizando funciones, estructuras de datos inmutables y un entorno interactivo basado en REPL. Su sintaxis es muy diferente a Java porque utiliza expresiones con muchos paréntesis, y aunque tiene una comunidad más pequeña, es especialmente valorado en sistemas backend, procesamiento de datos y aplicaciones donde la <strong>concurrencia y la programación funcional</strong> son importantes.</p>
<p><strong>Clojure fue creado por Rich Hickey</strong> y lanzado públicamente en <strong>2007</strong>. Hickey diseñó el lenguaje con el objetivo de simplificar el desarrollo de software concurrente y aprovechar la robustez de la plataforma Java, combinando las ideas de los lenguajes Lisp con conceptos modernos de programación funcional e inmutabilidad. Actualmente, Rich Hickey es una figura muy influyente en la comunidad de arquitectura de software y programación funcional.</p>
<h1><strong>Cómo instalar Clojure y empezar con ejemplos prácticos</strong></h1>
<p>Si estás comenzando con Clojure, el mejor camino es instalar la CLI oficial, abrir un REPL y practicar con funciones pequeñas que te ayuden a entender el estilo de programación funcional de esta herramienta.</p>
<p>Este primer post reúne la instalación paso a paso y varios ejemplos que ya hemos trabajado en este proyecto para que puedas compartirlo con tu comunidad de forma clara y útil.</p>
<p>Github Repo: <a href="https://github.com/joedayz/clojure-senior-path">https://github.com/joedayz/clojure-senior-path</a></p>
<h2><strong>1) Instalación de Clojure</strong></h2>
<h3><strong>macOS con Homebrew</strong></h3>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<pre><code class="language-shell">brew install clojure/tools/clojure
</code></pre>
<h3><strong>Linux (script oficial)</strong></h3>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<pre><code class="language-shell">curl -O https://download.clojure.org/install/linux-install-1.11.1.1403.sh
chmod +x linux-install-1.11.1.1403.sh
sudo ./linux-install-1.11.1.1403.sh
</code></pre>
<h3><strong>Windows</strong></h3>
<ol>
<li><p>Instala Java 21 o superior.</p>
</li>
<li><p>Instala la Clojure CLI con <code>winget</code>:</p>
</li>
</ol>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<pre><code class="language-shell">winget install clojure
</code></pre>
<h2><strong>2) Verificación de la instalación</strong></h2>
<p>Ejecuta estas instrucciones para confirmar que todo quedó bien instalado:</p>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<pre><code class="language-shell">java -version
clojure -Sdescribe
</code></pre>
<p>Si quieres ejecutar pruebas del proyecto:</p>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<pre><code class="language-shell">clojure -M:test -m cognitect.test-runner
</code></pre>
<blockquote>
<p>Si <code>clj</code> falla por un problema con <code>rlwrap</code>, usa <code>clojure</code> directamente. En muchos entornos, <code>clojure</code> es la opción más confiable.</p>
</blockquote>
<h2><strong>3) Primer contacto con el REPL</strong></h2>
<p>El REPL es una de las mejores partes de Clojure. Te permite evaluar expresiones inmediatas y probar ideas en tiempo real.</p>
<pre><code class="language-java">(+ 2 3)
(* 5 6)
(str "Hola" " Clojure")
</code></pre>
<p>También puedes probar operaciones con colecciones:</p>
<pre><code class="language-java">(def numbers [12345])
(map #(* 2 %) numbers)
(reduce + 0 numbers)
(filter even? numbers)
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<h2><strong>4) Ejemplos básicos que ya hemos practicado</strong></h2>
<h3><strong>a) Duplicar cada número</strong></h3>
<pre><code class="language-java">(defn double-all  
  [numbers]
  (map #(* 2 %) numbers))
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Uso:</p>
<pre><code class="language-java">(double-all [1 2 3 4])
;; =&gt; (2 4 6 8)
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<h3><strong>b) Sumar todos los elementos</strong></h3>
<pre><code class="language-java">(defn sum-numbers  
  [numbers]
  (reduce + 0 numbers))
</code></pre>
<p>Uso:</p>
<pre><code class="language-java">(sum-numbers [1 2 3 4])
;; =&gt; 10
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<h3><strong>c) Filtrar solo números pares</strong></h3>
<pre><code class="language-java">(defn even-only  [numbers]
  (filter even? numbers))
</code></pre>
<p>Uso:</p>
<pre><code class="language-java">(even-only [1 2 3 4 5 6])
;; =&gt; (2 4 6)
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<h3><strong>d) Contar vocales en un texto</strong></h3>
<pre><code class="language-java">(defn count-vowels  
  [text]
  (let [lower (clojure.string/lower-case text)
        vowels #{\a\e\i\o\u}]
    (count (filter vowels lower))))
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Uso:</p>
<pre><code class="language-plaintext">(count-vowels "Hola Mundo")
;; =&gt; 4
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<h3><strong>e) Factorial con</strong> <code>loop/recur</code></h3>
<pre><code class="language-java">(defn factorial  
  [n]
  (loop [current n acc 1]
    (if (&lt;=current 1)
      acc      
      (recur (dec current) (* acc current)))))
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Uso:</p>
<pre><code class="language-java">(factorial 5)
;; =&gt; 120
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Este ejemplo es útil para entender cómo Clojure maneja la recursión sin caer en problemas de stack overflow cuando se usa <code>loop/recur</code>.</p>
<h3><strong>f) Promedio de una colección</strong></h3>
<pre><code class="language-java">(defn average  
  [numbers]
  (if (empty? numbers)
    0    
    (/ (reduce + 0 numbers)
       (count numbers))))
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Uso:</p>
<pre><code class="language-java">(average [10 20 30])
;; =&gt; 20
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<h2><strong>5) Trabajar con maps y datos estructurados</strong></h2>
<p>Clojure es muy cómodo para trabajar con mapas, y esto se vuelve muy útil cuando construimos datos de negocio o modelos simples.</p>
<h3><strong>Crear un usuario normalizado</strong></h3>
<pre><code class="language-java">(defn build-user  
  [{:keys [id name email]}]
  {:id id
   :name name
   :email email
   :active true})
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Uso:</p>
<pre><code class="language-java">(build-user {:id 1 :name "Ana" :email "ana@example.com"})
;; =&gt; {:id 1, :name "Ana", :email "ana@example.com", :active true}
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<h3><strong>Resumen de producto</strong></h3>
<pre><code class="language-java">(defn product-summary  
  [{:keys [name price stock]}]
  {:name name
   :price price
   :stock stock
   :in-stock? (pos? stock)})
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<p>Uso:</p>
<pre><code class="language-java">(product-summary {:name "Laptop" :price 999 :stock 12})
;; =&gt; {:name "Laptop", :price 999, :stock 12, :in-stock? true}
</code></pre>
<img src="http://localhost:63342/markdownPreview/455488292//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles" alt="" style="display:block;margin:0 auto" />

<h2><strong>6) Por qué Clojure valora este enfoque</strong></h2>
<p>Los ejemplos anteriores muestran algunas ideas clave de Clojure:</p>
<ul>
<li><p>Las funciones son primero-class citizens.</p>
</li>
<li><p>Los datos son expresivos y fáciles de manipular.</p>
</li>
<li><p>Las colecciones se procesan con funciones como <code>map</code>, <code>filter</code> y <code>reduce</code>.</p>
</li>
<li><p>La recursión se maneja de forma clara con <code>loop/recur</code>.</p>
</li>
<li><p>Los maps permiten modelar información de una manera muy directa.</p>
</li>
</ul>
<h2><strong>7) Siguiente paso recomendado</strong></h2>
<p>Para seguir avanzando, te recomiendo practicar en este orden:</p>
<ol>
<li><p>Instalar la Clojure CLI.</p>
</li>
<li><p>Abrir el REPL y probar cada ejemplo manualmente.</p>
</li>
<li><p>Reescribir las funciones sin mirar el código.</p>
</li>
<li><p>Agregar nuevas pruebas con <code>clojure.test</code>.</p>
</li>
<li><p>Comenzar a crear pequeños ejercicios con maps y colecciones.</p>
</li>
</ol>
<h2><strong>8) Cierre</strong></h2>
<p>Clojure puede verse desafiante al principio, pero cuando entiendes el flujo de datos y la sintaxis básica, se vuelve muy elegante y poderosa. El primer objetivo no es dominar todo desde el inicio, sino construir confianza con ejemplos pequeños y repetibles.</p>
<p>En el siguiente post podemos continuar con una introducción a:</p>
<ul>
<li><p><code>let</code>, <code>if</code>, <code>cond</code> y <code>fn</code></p>
</li>
<li><p>listas, vectores y mapas</p>
</li>
<li><p><code>reduce</code>, <code>map</code> y <code>filter</code> en profundidad</p>
</li>
<li><p>cómo estructurar un proyecto con namespaces y tests</p>
</li>
</ul>
<p>Y así seguiremos compartiendo contenido útil para la comunidad de Clojure.</p>
<p>Enjoy!</p>
<p>Joe</p>
]]></content:encoded></item><item><title><![CDATA[kcp-commands & kcp-memory: las dos herramientas que le dan memoria a Claude Code en proyectos Java]]></title><description><![CDATA[Línea de apertura (opcional, para el feed): Claude Code empieza cada sesión desde cero. No recuerda qué archivos modificaste ayer. No recuerda el bug que…]]></description><link>https://joedayz.hashnode.dev/kcp-commands-kcp-memory-las-dos-herramientas-que-le-dan-memoria-a-claude-code-en-proyectos-java</link><guid isPermaLink="true">https://joedayz.hashnode.dev/kcp-commands-kcp-memory-las-dos-herramientas-que-le-dan-memoria-a-claude-code-en-proyectos-java</guid><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Fri, 31 Jul 2026 23:31:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/71a39364-80e8-4fcb-acd7-4ac86de53999.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Línea de apertura (opcional, para el feed):</strong> Claude Code empieza cada sesión desde cero. No recuerda qué archivos modificaste ayer. No recuerda el bug que arreglaste la semana pasada. No recuerda que <code>mvn clean install</code> genera 800 líneas de las cuales solo 8 importan. Dos herramientas del ecosistema KCP resuelven exactamente eso.</p>
<p><em>Basado en la presentación "KCP-COMMANDS &amp; KCP-MEMORY" (SDD Breakout — Herramientas ExoCortex) de Jose Diaz Diaz · Autor: Thor Henning Hetland (Totto) · Ægis, Santiago de los Caballeros 2026, y en</em> <a href="https://wiki.totto.org/blog/2026/07/17/the-kcp-ecosystem-a-tour-for-new-arrivals/"><em>The KCP Ecosystem: A Tour for New Arrivals</em></a> <em>(Thor Henning Hetland, julio 2026).</em></p>
<p>El artículo anterior de esta serie presentó el <code>knowledge.yaml</code> como el índice de navegación que le dice a la IA dónde está todo al inicio de sesión. Eso resuelve el problema del <strong>descubrimiento</strong>.</p>
<p>Pero hay dos problemas que el <code>knowledge.yaml</code> solo no resuelve:</p>
<ol>
<li><p><strong>Context window burn</strong>: <code>mvn test</code> genera 500+ líneas. <code>git log --oneline</code> genera 200+ líneas. La IA consume tokens procesando ruido que nunca necesitó ver.</p>
</li>
<li><p><strong>Session amnesia</strong>: Cada sesión nueva es una pizarra en blanco. El agente no sabe que la semana pasada arreglaste el N+1 query en <code>OrderRepository</code>. No sabe que el refactor de autenticación dejó tres TODOs pendientes. No sabe que decidiste usar <code>@Tag("integration")</code> para separar tests que necesitan Docker.</p>
</li>
</ol>
<p><code>kcp-commands</code> resuelve el primero. <code>kcp-memory</code> resuelve el segundo. Están diseñados para usarse juntos.</p>
<h2><strong>El mapa del problema</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/0052e01d-d9a6-42f7-b115-2a5ba509f35f.png" alt="" style="display:block;margin:0 auto" />

<p><code>kcp-commands</code> y <code>kcp-memory</code> trabajan en cadena: el hook escribe el log de eventos, el daemon indexa ese log y lo convierte en memoria recuperable.</p>
<p><code>kcp-commands</code> es un <a href="https://docs.anthropic.com/en/docs/claude-code/hooks">PreToolUse + PostToolUse hook</a> de Claude Code. Se dispara en <strong>cada llamada Bash</strong> del agente, en tres fases consecutivas.</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/c3f0279f-e32a-432f-b4b9-e811d125e5a9.png" alt="" style="display:block;margin:0 auto" />

<h3><strong>Fase A: antes de ejecutar — inyección de guía</strong></h3>
<p>Para comandos reconocidos, el hook inyecta un hint compacto con los flags que el agente probablemente necesita. En lugar de que Claude Code adivine los parámetros de <code>mvn</code> o <code>kubectl</code>, recibe una guía concisa antes de ejecutar.</p>
<p>Para Java developers, esto cubre:</p>
<ul>
<li><p><code>mvn</code> / <code>./mvnw</code> — surefire flags, perfiles, skip tests</p>
</li>
<li><p><code>git</code> — status, diff, log, branch, cherry-pick</p>
</li>
<li><p><code>docker</code> / <code>docker-compose</code> — ps, logs, build, push</p>
</li>
<li><p><code>kubectl</code> — get pods, describe, logs, apply</p>
</li>
</ul>
<h3><strong>Fase B: después de ejecutar — filtrado de output</strong></h3>
<p>Esta es la fase de mayor impacto en context window. El manifiesto de cada comando define qué líneas conservar y qué desechar:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/bf413ebc-338b-4dad-ac97-453ed4664b8c.png" alt="" style="display:block;margin:0 auto" />

<p>El manifest para <code>mvn test</code> se ve así (formato interno del hook):</p>
<pre><code class="language-yaml"># ~/.kcp/manifests/mvn-test.yaml
command: "mvn.*test|./mvnw.*test"
phase_a:
  inject: |
    Flags útiles: -pl &lt;módulo&gt; para módulo específico,
    -Dtest=NombreTest para test único,
    -DskipTests para compilar sin ejecutar.
phase_b:
  filter: keep_matching
  patterns:
    - "BUILD (SUCCESS|FAILURE)"
    - "Tests run:"
    - "FAILED:"
    - "ERROR:"
    - "\\[ERROR\\]"
  inject_on_failure: |
    Si hay fallos con @Tag("integration"), pueden necesitar
    la infraestructura de Docker levantada con docker-compose.
phase_c:
  log: true
</code></pre>
<h3><strong>Fase C: event logging</strong></h3>
<p>Cada llamada Bash queda registrada en <code>~/.kcp/events.jsonl</code>. Este log es el insumo que consume <code>kcp-memory</code>. Sin <code>kcp-commands</code>, <code>kcp-memory</code> no tiene datos que indexar.</p>
<pre><code class="language-jsonl">{"ts":"2026-07-31T09:14:22Z","cmd":"mvn test","project":"pedidos-api","exit":1,"summary":"FAILED: OrderServiceTest (1 failure)","filtered_lines":8,"original_lines":847}
{"ts":"2026-07-31T09:18:44Z","cmd":"git diff HEAD~1","project":"pedidos-api","exit":0,"summary":"Modified: OrderService.java, OrderRepository.java","filtered_lines":12,"original_lines":234}
{"ts":"2026-07-31T09:25:01Z","cmd":"mvn test","project":"pedidos-api","exit":0,"summary":"Tests run: 47, Failures: 0","filtered_lines":3,"original_lines":812}
</code></pre>
<h3><strong>Impacto medido</strong></h3>
<table>
<thead>
<tr>
<th>Métrica</th>
<th>Valor</th>
</tr>
</thead>
<tbody><tr>
<td>Ahorro de context window por sesión</td>
<td><strong>33% promedio</strong></td>
</tr>
<tr>
<td>Comandos cubiertos por manifests</td>
<td><strong>84% de las llamadas Bash típicas</strong></td>
</tr>
<tr>
<td>Latencia del hook (JVM)</td>
<td><strong>12 ms por llamada</strong></td>
</tr>
<tr>
<td>Manifests incluidos</td>
<td><strong>292</strong></td>
</tr>
<tr>
<td>Configuración requerida</td>
<td><strong>0</strong></td>
</tr>
</tbody></table>
<p>El hook funciona out of the box. No requiere ningún <code>knowledge.yaml</code>. No requiere configurar manifests. Instálalo y empieza a ahorrar tokens en la próxima sesión.</p>
<h3><strong>Instalación</strong></h3>
<pre><code class="language-bash"># Opción recomendada — daemon Java (12 ms/call):
curl -fsSL https://raw.githubusercontent.com/Cantara/kcp-commands/main/bin/install.sh | bash -s -- --java

# Alternativa — solo Node.js (no requiere JVM):
curl -fsSL https://raw.githubusercontent.com/Cantara/kcp-commands/main/bin/install.sh | bash -s -- --node
</code></pre>
<p>El installer registra el hook en el <code>settings.json</code> global de Claude Code. Después del primer <code>claude</code> que ejecutes, el hook está activo.</p>
<h2><strong>kcp-memory: memoria episódica cross-session</strong></h2>
<p>Repo: <a href="https://github.com/Cantara/kcp-memory">github.com/Cantara/kcp-memory</a> · Versión: 0.32.0</p>
<p>Los agentes son amnésicos por diseño. Cada sesión nueva empieza desde cero. <code>kcp-memory</code> cierra ese hueco.</p>
<h3><strong>El problema concreto en un proyecto Java</strong></h3>
<p>Imagina este escenario real en un proyecto Spring Boot:</p>
<ul>
<li><p><strong>Lunes</strong>: Debuggeas un N+1 query. Encuentras que <code>OrderRepository.findByCustomer()</code> hace lazy loading mal configurado. Arreglas con <code>@EntityGraph</code>. 45 minutos de investigación.</p>
</li>
<li><p><strong>Martes</strong>: Nueva sesión. Pides a Claude que optimice queries en el módulo de clientes. El agente vuelve a investigar el mismo patrón de lazy loading. 30 minutos para redescubrir lo que ya sabes.</p>
</li>
<li><p><strong>Miércoles</strong>: Refactorizas autenticación. Dejas 3 TODOs marcados en JWT config. Sesión termina antes de completarlos.</p>
</li>
<li><p><strong>Jueves</strong>: Nueva sesión. No hay contexto de los TODOs. El agente no sabe qué estaba en progreso.</p>
</li>
</ul>
<p><code>kcp-memory</code> convierte el martes, miércoles y jueves en sesiones que arrancan informadas.</p>
<h3><strong>Cómo funciona el daemon</strong></h3>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/28ef06d8-5f7b-44ba-a28f-aa2dd3509cf7.png" alt="" style="display:block;margin:0 auto" />

<h3><strong>Qué captura kcp-memory</strong></h3>
<p>El daemon indexa y prioriza cuatro categorías de información:</p>
<table>
<thead>
<tr>
<th>Categoría</th>
<th>Ejemplo Java</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Bugs descubiertos y cómo se arreglaron</strong></td>
<td>"N+1 en OrderRepository — @EntityGraph"</td>
</tr>
<tr>
<td><strong>Decisiones de arquitectura de la sesión</strong></td>
<td>"Usamos MapStruct en vez de ModelMapper — ADR-012"</td>
</tr>
<tr>
<td><strong>Archivos tocados y por qué</strong></td>
<td>"<a href="http://JwtTokenProvider.java">JwtTokenProvider.java</a> — refactor expiración tokens"</td>
</tr>
<tr>
<td><strong>Patrones extraídos como nuevas skills</strong></td>
<td>"<a href="http://jakarta-migration.md">jakarta-migration.md</a> — javax→jakarta en imports"</td>
</tr>
<tr>
<td><strong>Issues recurrentes entre sesiones</strong></td>
<td>"Port 5432 conflicto — usar POSTGRES_PORT=5433"</td>
</tr>
</tbody></table>
<h3><strong>La diferencia práctica</strong></h3>
<p>Lo que Claude ve al abrir una sesión nueva en tu proyecto Spring Boot:</p>
<pre><code class="language-markdown">## Relevant session history — pedidos-api

2026-07-28: Fixed N+1 query in OrderRepository.findByCustomer().
Cause: default lazy loading on @OneToMany. Fix: @EntityGraph annotation.
Added pattern to performance-patterns.md skill.

2026-07-29: JWT refactor session ended mid-task.
3 TODOs pending in src/main/java/.../security/JwtTokenProvider.java (lines 87, 134, 201).
Context: expiry was calculated in seconds not ms — see PR #1847.

2026-07-30: Integration test failures.
Cause: docker-compose postgres port 5432 conflicts with local instance.
Fix: POSTGRES_PORT=5433 in .env.test
</code></pre>
<p>En lugar de empezar a explorar desde cero, el agente arranca con el contexto de lo que pasó — los problemas activos, las decisiones tomadas, los archivos en progreso.</p>
<h3><strong>Memoria compartida entre sub-agentes</strong></h3>
<p>kcp-memory indexa también los transcripts de sub-agentes. Esto significa que si usas <a href="https://docs.anthropic.com/en/docs/claude-code/sub-agents">Task tool o sub-agentes paralelos</a> en Claude Code, la memoria es compartida entre todos ellos dentro del mismo proyecto. Un sub-agente que arregla tests y otro que refactoriza servicios ven el mismo contexto histórico.</p>
<h3><strong>Almacenamiento</strong></h3>
<p>SQLite local en <code>~/.kcp/memory.db</code>. Sin cloud. Sin envío de datos. El contexto inyectado al inicio de sesión es generado localmente por el daemon.</p>
<h3><strong>Instalación</strong></h3>
<pre><code class="language-bash"># Instalar kcp-memory (requiere kcp-commands instalado primero):
# Ver instrucciones actualizadas en:
# https://github.com/Cantara/kcp-memory#install
</code></pre>
<h2><strong>Cómo funcionan juntos: la cadena completa</strong></h2>
<p><code>kcp-commands</code> + <code>kcp-memory</code> forman un sistema de dos capas:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/f71c8a46-e0da-4fac-9434-851a7984b820.png" alt="" style="display:block;margin:0 auto" />

<p>La clave es que son independientes pero complementarios:</p>
<ul>
<li><p><strong>kcp-commands solo</strong>: ahorra context window en la sesión actual. Sin memoria cross-session.</p>
</li>
<li><p><strong>kcp-memory solo</strong>: sin eventos que indexar (no hay <code>events.jsonl</code>), opera solo con transcripts de sesión — útil pero limitado.</p>
</li>
<li><p><strong>Ambos juntos</strong>: ahorro de tokens + contexto histórico enriquecido = el loop completo.</p>
</li>
</ul>
<h2><strong>Plan de adopción para un proyecto Java existente</strong></h2>
<p>No es necesario instalar todo a la vez. El ecosistema está diseñado para adopción incremental:</p>
<h3><strong>Día 1 — Ahorro de context window inmediato</strong></h3>
<pre><code class="language-bash"># Instalar kcp-commands (Java daemon):
curl -fsSL https://raw.githubusercontent.com/Cantara/kcp-commands/main/bin/install.sh | bash -s -- --java

# Abrir Claude Code. Ejecutar cualquier comando Maven o Git.
# Observar: la Fase A inyecta hints antes del comando.
# Observar: la Fase B devuelve output filtrado.
# El ahorro empieza desde la primera sesión.
</code></pre>
<h3><strong>Día 2 — Agregar memoria episódica</strong></h3>
<pre><code class="language-bash"># Instalar kcp-memory:
# https://github.com/Cantara/kcp-memory#install

# El daemon empieza a indexar events.jsonl y transcripts.
# La próxima sesión recibirá contexto de la sesión de hoy.
</code></pre>
<h3><strong>Día 3 — Agregar inteligencia de workspace (opcional)</strong></h3>
<pre><code class="language-bash"># Configurar Synthesis MCP en .claude/mcp.json
# Luego: synthesis scan . (desde la raíz del proyecto)
# Claude Code puede buscar, relacionar y preguntar sobre todo el codebase.
</code></pre>
<h3><strong>Cuando necesites governance:</strong></h3>
<p>Agrega <code>kcp-agent</code> para load planning inspeccionable, y <code>kcp-harness</code> para enforcement. Estos son para cuando los agentes corren en producción o en entornos donde "el agente leyó el archivo X porque..." necesita ser auditable.</p>
<h2><strong>Manifest personalizado para tu proyecto Java</strong></h2>
<p>Si tu proyecto tiene patrones específicos — un wrapper de Maven, un runner de tests con flags especiales, un CLI interno — puedes agregar manifests propios en <code>~/.kcp/manifests/</code>:</p>
<pre><code class="language-yaml"># ~/.kcp/manifests/my-project-test.yaml
command: "./scripts/run-tests.sh"
phase_a:
  inject: |
    Flags disponibles: --module &lt;nombre&gt;, --tag integration, --tag unit.
    Los tests de integración requieren: docker-compose up -d postgres redis
phase_b:
  filter: keep_matching
  patterns:
    - "PASSED|FAILED|ERROR"
    - "Tests run:"
    - "\\[WARN\\].*important"
  inject_on_failure: |
    Revisar logs en target/surefire-reports/ para stack traces completos.
phase_c:
  log: true
</code></pre>
<p>Los 292 manifests incluidos cubren las herramientas más comunes. Los manifests propios se fusionan sin sobreescribir los del sistema.</p>
<hr />
<h2><strong>Qué resuelven estas herramientas y qué no</strong></h2>
<table>
<thead>
<tr>
<th>Problema</th>
<th>Herramienta</th>
</tr>
</thead>
<tbody><tr>
<td>"mvn test genera 800 líneas de ruido"</td>
<td>✅ kcp-commands Fase B</td>
</tr>
<tr>
<td>"La IA no sabe los flags correctos de kubectl"</td>
<td>✅ kcp-commands Fase A</td>
</tr>
<tr>
<td>"Mañana la IA no recuerda el bug que arreglé hoy"</td>
<td>✅ kcp-memory</td>
</tr>
<tr>
<td>"La IA no sabe la arquitectura del proyecto"</td>
<td><a href="http://CLAUDE.md">CLAUDE.md</a> + knowledge.yaml</td>
</tr>
<tr>
<td>"La IA no puede buscar en el codebase"</td>
<td>Synthesis</td>
</tr>
<tr>
<td>"Necesito auditar qué cargó el agente"</td>
<td>kcp-agent + kcp-harness</td>
</tr>
</tbody></table>
<p><code>kcp-commands</code> y <code>kcp-memory</code> son la entrada más directa al ecosistema KCP: impacto inmediato, configuración cero, instalación en dos comandos.</p>
<hr />
<h2><strong>Recursos</strong></h2>
<ul>
<li><p><a href="https://github.com/Cantara/kcp-commands">kcp-commands — GitHub</a></p>
</li>
<li><p><a href="https://github.com/Cantara/kcp-memory">kcp-memory — GitHub</a></p>
</li>
<li><p><a href="https://wiki.totto.org/blog/2026/07/17/the-kcp-ecosystem-a-tour-for-new-arrivals/">The KCP Ecosystem: A Tour for New Arrivals</a> — Thor Henning Hetland</p>
</li>
<li><p><a href="https://github.com/Cantara/knowledge-context-protocol">Knowledge Context Protocol spec</a></p>
</li>
<li><p><a href="https://file+.vscode-resource.vscode-cdn.net/Users/josediaz/Projects/JoeDayz/articulos-joedayz/blog-kcp-knowledge-context-protocol-java.md">Artículo anterior: KCP — el protocolo de navegación</a></p>
</li>
</ul>
<hr />
<p><em>Enjoy!</em></p>
<p><em>Joe</em></p>
]]></content:encoded></item><item><title><![CDATA[KCP: el protocolo que hace que tu IA deje de explorar y empiece a trabajar]]></title><description><![CDATA[Línea de apertura (opcional, para el feed): En cada sesión nueva, Claude abre el README, escanea el árbol de directorios, busca el pom.xml, encuentra…]]></description><link>https://joedayz.hashnode.dev/kcp-el-protocolo-que-hace-que-tu-ia-deje-de-explorar-y-empiece-a-trabajar</link><guid isPermaLink="true">https://joedayz.hashnode.dev/kcp-el-protocolo-que-hace-que-tu-ia-deje-de-explorar-y-empiece-a-trabajar</guid><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Fri, 31 Jul 2026 19:45:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/2fd29e29-4302-4a2c-be25-191a16dedc85.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Línea de apertura (opcional, para el feed):</strong> En cada sesión nueva, Claude abre el README, escanea el árbol de directorios, busca el <code>pom.xml</code>, encuentra <code>src/main/java</code>... 33 tool calls para orientarse. Con un archivo de 50 líneas en la raíz del proyecto, eso baja a 3. Mismo codebase. Mucho menos tiempo perdido.</p>
<p><em>Basado en la presentación de Thor Henning Hetland (Totto) · Ægis,</em> <a href="https://wiki.totto.org/blog/2026/07/29/the-kcp-universe-everything-and-what-july-changed/"><em>The KCP Universe: Everything, and What July Changed</em></a> <em>(v0.30.3, 29 julio 2026).</em></p>
<hr />
<p>El Pilar 1 de esta serie explica cómo construir el <a href="http://CLAUDE.md"><code>CLAUDE.md</code></a> con el ADN del proyecto: convenciones, anti-patrones, flujo de Git, requisitos de testing. Es el conocimiento del codebase.</p>
<p>Pero hay un problema que el <a href="http://CLAUDE.md"><code>CLAUDE.md</code></a> no resuelve: <strong>la IA tiene que encontrarlo</strong>.</p>
<p>En cada sesión nueva con Claude Code, el agente empieza desde cero. No recuerda dónde está el <a href="http://CLAUDE.md"><code>CLAUDE.md</code></a>. No sabe que el proyecto tiene arquitectura hexagonal con cuatro capas de paquetes. No sabe que los skills están en <code>.claude/skills/</code>. Tiene que descubrirlo leyendo archivos, escaneando directorios y abriendo configuraciones.</p>
<p>En un proyecto Java típico, eso cuesta entre 20 y 33 tool calls antes de que el agente pueda empezar la primera tarea.</p>
<p>El <strong>Knowledge Context Protocol</strong> (KCP) resuelve exactamente eso.</p>
<h2><strong>El problema: relevancia no es autoridad</strong></h2>
<p>Antes de ver la solución, vale la pena entender por qué el problema es más profundo de lo que parece.</p>
<p>Un agente leyendo tu codebase no tiene forma de saber qué es verdad. Encuentra un documento de arquitectura de marzo y uno de junio. Nada en ninguno de los dos dice cuál es el actual. Sigue el runbook que fue supersedido en abril. Lee la guía de API interna escrita para una versión que ya no existe. Los lee todos con exactamente la misma confianza, porque un archivo es un archivo.</p>
<p>El Retrieval Augmented Generation (RAG) no resuelve esto. RAG encuentra texto <em>relevante</em>. No tiene concepto de texto <em>autoritativo</em>. Relevancia y autoridad son preguntas distintas, y solo una de ellas tiene una respuesta que se puede verificar.</p>
<p>KCP es la otra respuesta.</p>
<h2><strong>Qué es KCP: dos mecanismos, un archivo</strong></h2>
<p>Un <code>knowledge.yaml</code> en la raíz del repositorio. La IA lo lee primero, al inicio de cada sesión, y se orienta en 3 tool calls en lugar de 33.</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/173eb34e-100c-4f4e-974f-fffae5568594.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/92ae083a-02e8-4c84-b2fc-34fad30d4342.png" alt="" style="display:block;margin:0 auto" />

<p>El <code>knowledge.yaml</code> hace dos trabajos distintos:</p>
<p><strong>Mecanismo 1 — Índice de navegación del proyecto:</strong> Declara arquitectura, ubicaciones de skills, convenciones, puntos de entrada y paths clave. La IA lo lee una vez al inicio de sesión y conoce la estructura del proyecto sin explorar.</p>
<blockquote>
<p><a href="http://CLAUDE.md"><code>CLAUDE.md</code></a> es conocimiento. <code>knowledge.yaml</code> es navegación.</p>
</blockquote>
<p><strong>Mecanismo 2 — Command manifests:</strong> Interceptan el output de CLI antes de que la IA lo procese. <code>git status</code> en un repo grande genera 200+ líneas; el manifest lo filtra a las 12 relevantes. <code>mvn test</code> genera 500+ líneas de INFO y descargas; el manifest devuelve solo los fallos.</p>
<p>Resultado medido: <strong>33% del context window ahorrado por sesión</strong> en operaciones rutinarias de desarrollo. 60–80% en operaciones con output especialmente verboso.</p>
<h2><strong>Cómo se ve en un proyecto Java Spring Boot</strong></h2>
<pre><code class="language-yaml"># knowledge.yaml — raíz del repositorio
project:
  name: pedidos-api
  type: java-spring-boot
  architecture: CLAUDE.md#architecture

skills:
  global: ~/.claude/skills/common/
  project: .claude/skills/
  navigator: .claude/skills/navigator.yaml

entry_points:
  - src/main/java/com/empresa/pedidos/PedidosApplication.java
  - src/main/java/com/empresa/pedidos/api/

conventions:
  - CLAUDE.md#conventions
  - docs/ADRs/

commands:
  maven_test:
    filter: failures_only
    ignore: ["^\\[INFO\\]", "^\\[WARNING\\]", "Downloading:", "Downloaded:"]
    inject: "Verifica si los fallos tienen @Tag de integración — pueden requerir Docker"

  git_status:
    filter: staged_only
    ignore: ["target/", ".mvn/", "*.class", "*.jar"]
    inject: "Verifica que no se modificaron archivos de corpus de tests"

  maven_compile:
    filter: errors_only
    ignore: ["^\\[INFO\\]", "^\\[WARNING\\]"]
    inject: "Si hay errores de javax.*, revisar migración jakarta — ver CLAUDE.md#antipatrones"
</code></pre>
<p>El impacto concreto del filtrado de <code>mvn test</code>:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/94b573c4-5a76-4dc9-b6d0-533a3ee5a649.png" alt="" style="display:block;margin:0 auto" />

<h2><strong>Los tres artefactos que KCP gobierna</strong></h2>
<p>Con la versión v0.29 (julio 2026), el protocolo introdujo tres clases de artefactos que cambian la naturaleza de lo que puede gobernar:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/8a7f9295-d3f8-4621-b2db-1b0958d78756.png" alt="" style="display:block;margin:0 auto" />

<p>La distinción que más importa para Java devs:</p>
<ul>
<li><p>Una <strong>unidad de conocimiento</strong> (<code>kind: knowledge</code>) es un hecho: el ADR que explica por qué el equipo usa hexagonal, el documento que dice que <code>monto</code> siempre es <code>BigDecimal</code>. Puede tener <code>valid_until</code> y expira solo cuando caduca.</p>
</li>
<li><p>Un <strong>skill</strong> (<code>kind: skill</code>) es un procedimiento sobre una cosa: cómo migrar un controlador Spring Boot 2 a 3, cómo generar un DTO con record. Tiene <code>action_scope</code> declarado — qué herramientas puede usar — y el agente no puede salirse de ese scope sin que el harness lo bloquee.</p>
</li>
<li><p>Un <strong>playbook</strong> (<code>kind: playbook</code>, nuevo en v0.29) es un objetivo compuesto: "actualizar Spring Boot de 2.x a 3.x en este módulo". Contiene una secuencia de skills con checkpoints. Al terminar, emite una cadena de decisiones firmada — no un log, sino evidencia criptográfica de que cada paso se ejecutó dentro de lo que estaba autorizado a hacer.</p>
</li>
</ul>
<h2><strong>La unidad de confianza: qué dice un entry de knowledge.yaml</strong></h2>
<pre><code class="language-yaml"># Ejemplo de unidad de skill declarada en knowledge.yaml
- id: jakarta-migration-skill
  path: .claude/skills/jakarta-migration.md
  kind: skill
  intent: "Migración de javax.* a jakarta.* en controladores Spring Boot 3.
           Incluye anotaciones OpenAPI 3 y tests MockMvc actualizados."
  scope: project
  audience: [agent]
  triggers: [jakarta, javax, spring-boot-3, migration]
  load_eligible: true
  action_scope:
    tools: ["read_file", "replace_string_in_file"]
  valid_until: "2027-01-01"
</code></pre>
<p>Cada campo responde una pregunta que el agente de otra forma tendría que adivinar:</p>
<ul>
<li><p><code>intent</code> — ¿para qué sirve esto? No un resumen del texto; una declaración de propósito.</p>
</li>
<li><p><code>audience: [agent]</code> — ¿es para mí? Un doc de onboarding humano y un runbook de agente son artefactos distintos.</p>
</li>
<li><p><code>kind: skill</code> — ¿es conocimiento o un procedimiento? Esta línea hace que la unidad sea gobernable como acción.</p>
</li>
<li><p><code>load_eligible: true</code> — ¿se puede cargar? La elegibilidad es separada de la relevancia.</p>
</li>
<li><p><code>action_scope</code> — ¿qué puede tocar? Una tool call fuera de <code>read_file</code> y <code>replace_string_in_file</code> es rechazada en el loop, con la razón escrita.</p>
</li>
</ul>
<h2><strong>Lo que cambió en julio 2026 (v0.28–v0.30.3)</strong></h2>
<p>El protocolo pasó de v0.22 a v0.30.3 en julio con 1.012 commits y 88 releases. Cuatro cambios que importan para quienes lo usan:</p>
<ol>
<li><p>Paridad de implementaciones (v0.28) KCP tiene bridges para TypeScript, Java y Python. Hasta julio, "la spec dice X" y "las implementaciones hacen X" eran claims separados. v0.28 los unificó con vectores de conformance compartidos. Una diferencia entre el parser Java y el Python ahora es un test failure, no un descubrimiento en producción seis semanas después.</p>
</li>
<li><p>El plano procedimental — kind: playbook (v0.29) Antes KCP gobernaba hechos. Ahora también puede gobernar objetivos compuestos. Un playbook emite una cadena de decisiones firmada — evidencia que puede presentarse en una auditoría de cumplimiento.</p>
</li>
<li><p>Eligibility grants (v0.30) Un sistema de gobernanza que solo puede decir no es un freno. Los grants permiten que unidades sean elegibles bajo condiciones específicas, con el historial de qué se solicitó y qué se rechazó. La solicitud misma es parte del audit trail.</p>
</li>
<li><p>Parse diagnostics Antes de julio, un campo mal escrito (audiance: en lugar de audience:) se ignoraba silenciosamente. La unidad parseaba limpia y quedaba sin gobierno para siempre. Ahora lo dice.</p>
</li>
</ol>
<p>"El campo mal escrito es el mejor ejemplo del problema central: la diferencia entre algo que está bien y algo que no fue verificado es invisible a menos que construyas la maquinaria para verlo."</p>
<h2><strong>Por qué importa para proyectos Java en particular</strong></h2>
<p>Los proyectos Java son exactamente el tipo de codebase donde el problema de orientación es más costoso:</p>
<ul>
<li><p><strong>Multi-módulo Maven</strong>: <code>ls</code> en el root no dice nada. La estructura real está cuatro niveles abajo.</p>
</li>
<li><p><strong>Spring Boot conventions</strong>: La convención de paquetes, la separación de capas, los beans esperados — nada de esto es visible sin explorar.</p>
</li>
<li><p><strong>Output verboso de Maven</strong>: 500 líneas de INFO por cada <code>mvn test</code>. Sin filtrado, la IA gasta contexto en ruido que tú ya ignoras automáticamente.</p>
</li>
<li><p><strong>Migraciones largas</strong>: Una migración Spring Boot 2 → 3 abarca docenas de archivos con el mismo patrón. El playbook KCP puede gobernar cada paso con evidencia firmada.</p>
</li>
</ul>
<h2><strong>Cómo empezar: tres pasos</strong></h2>
<p><strong>Paso 1 — Instala</strong> <code>kcp-commands</code> (10 minutos, resultado inmediato)</p>
<p>Es el único punto de entrada con payoff inmediato sin conocer el protocolo. Envuelve comandos frecuentes (git, mvn) con filtrado token-eficiente. Corre como hook en ~12ms. No necesitas saber qué es KCP para beneficiarte.</p>
<p><strong>Paso 2 — Escribe un</strong> <code>knowledge.yaml</code> <strong>básico</strong> para tu proyecto Java</p>
<p>Seis unidades. Para cada una: <code>intent</code>, <code>audience</code>, y donde aplique <code>valid_until</code>. Luego:</p>
<pre><code class="language-bash">kcp-agent plan "migrar PedidoController a Spring Boot 3" \
  --manifest knowledge.yaml \
  --trace --json
</code></pre>
<p>Leer los 14 gate verdicts explicados por escrito es el momento en que el concepto aterriza.</p>
<h2><strong>La conexión con los 6 pilares</strong></h2>
<p>KCP no reemplaza al <a href="http://CLAUDE.md"><code>CLAUDE.md</code></a> del Pilar 1. Lo complementa:</p>
<table>
<thead>
<tr>
<th></th>
<th><a href="http://CLAUDE.md"><code>CLAUDE.md</code></a></th>
<th><code>knowledge.yaml</code></th>
</tr>
</thead>
<tbody><tr>
<td><strong>Qué es</strong></td>
<td>Conocimiento del codebase</td>
<td>Mapa de navegación del codebase</td>
</tr>
<tr>
<td><strong>Para quién</strong></td>
<td>La IA lee el contenido</td>
<td>La IA navega hacia el contenido</td>
</tr>
<tr>
<td><strong>Qué declara</strong></td>
<td>Convenciones, anti-patrones, errores comunes</td>
<td>Arquitectura, paths, skills, entry points</td>
</tr>
<tr>
<td><strong>Qué gobierna</strong></td>
<td>Comportamiento esperado</td>
<td>Qué puede cargar, qué puede tocar</td>
</tr>
</tbody></table>
<p>El Pilar 6 (volante de aprendizaje) actualiza el <a href="http://CLAUDE.md"><code>CLAUDE.md</code></a> con cada bug. KCP hace que esas actualizaciones sean encontrables y autoritativas, no solo relevantes.</p>
<blockquote>
<p>La estructura del flujo de trabajo no es una barrera para el código. Son los rieles que permiten al equipo ir a 300 km/h sin descarrilar.</p>
</blockquote>
<p>Los rieles funcionan mejor cuando la IA sabe dónde están desde el primer tool call.</p>
<hr />
<p><em>¿Cuántos tool calls hace Claude en tu proyecto Java antes de empezar la primera tarea? Puedes medirlo abriendo una sesión nueva y contando. Ese número es tu baseline de cold-start. ¿Cuánto mejoraría con un</em> <code>knowledge.yaml</code><em>?</em></p>
<p><em>Enjoy!</em></p>
<p><em>Joe</em></p>
]]></content:encoded></item><item><title><![CDATA[Pilar 6: El volante de aprendizaje de IA — cómo hacer que tu agente sea permanentemente más inteligente]]></title><description><![CDATA[Línea de apertura (opcional, para el feed): Llevas tres meses usando Claude en tu proyecto Java. Los mismos errores de hace tres meses siguen apareciendo…]]></description><link>https://joedayz.hashnode.dev/pilar-6-el-volante-de-aprendizaje-de-ia-c-mo-hacer-que-tu-agente-sea-permanentemente-m-s-inteligente</link><guid isPermaLink="true">https://joedayz.hashnode.dev/pilar-6-el-volante-de-aprendizaje-de-ia-c-mo-hacer-que-tu-agente-sea-permanentemente-m-s-inteligente</guid><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Fri, 31 Jul 2026 19:16:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/e896c655-1b2b-49d3-86f1-b035721dfb01.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Línea de apertura (opcional, para el feed):</strong> Llevas tres meses usando Claude en tu proyecto Java. Los mismos errores de hace tres meses siguen apareciendo. <code>==</code> para comparar <code>BigDecimal</code>. <a href="http://LocalDate.now"><code>LocalDate.now</code></a><code>()</code> directo en el dominio. <code>javax.*</code> en lugar de <code>jakarta.*</code>. El modelo no aprendió porque tú no le enseñaste. Este es el último pilar: convertir cada bug en inteligencia permanente.</p>
<p><em>Parte de la serie "Los 6 pilares del desarrollo asistido por IA" — basado en el material de Thor Henning Hetland (Totto) / Ægis. Adaptado a proyectos Java.</em></p>
<hr />
<p>Los cinco pilares anteriores construyen la base: contexto inteligente (Pilar 1), delegación estratégica (Pilar 2), verificación sistemática (Pilar 3), agencia técnica (Pilar 4) y guardrails de proceso (Pilar 5). El Pilar 6 responde la pregunta que todos estos dejan abierta:</p>
<p><strong>¿Cómo hace el sistema para volverse más inteligente con el tiempo, no solo más rápido?</strong></p>
<p>La respuesta no es confiar en que el modelo aprenda solo. Los modelos no aprenden de tus sesiones. Lo que aprendiste tú al arreglar ese bug el martes desaparece en el siguiente chat si no lo documentas. El Pilar 6 es el mecanismo para convertir cada bug resuelto, cada patrón descubierto y cada edge case encontrado en inteligencia permanente del sistema.</p>
<hr />
<h2><strong>El problema del contexto estático</strong></h2>
<p>Hay dos tipos de equipos que usan IA:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/b5ff193a-bdcf-471d-961b-cf1601495cca.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/d9faf747-7a27-4a4c-97a5-d14ef38a1ea8.png" alt="" style="display:block;margin:0 auto" />

<p>La diferencia no está en el modelo. Está en si el equipo actualiza el contexto o no.</p>
<p>Con el enfoque estático, el <a href="http://CLAUDE.md">CLAUDE.md</a> del Pilar 1 se queda exactamente igual que el día que se escribió. La IA no aprende que <code>BigDecimal</code> se compara con <code>.compareTo()</code>, no aprende que el endpoint <code>/pagos</code> tiene validaciones especiales antes del publish a Kafka, no aprende que <code>Optional.empty()</code> en <code>PedidoService.findById()</code> puede significar "cancelado" además de "no existe".</p>
<p>Con el enfoque continuo, cada bug que se arregla se convierte en un anti-patrón documentado. Cada patrón que funciona bien se convierte en una skill. Cada edge case descubierto se convierte en un requisito de test. La IA del mes 3 es cualitativamente diferente a la del día 1.</p>
<h2><strong>El volante: cómo funciona el mecanismo</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/27ded2c9-eed6-4f3f-ad19-d71401447f25.png" alt="" style="display:block;margin:0 auto" />

<p>El volante gira con tres artefactos:</p>
<ol>
<li><p><a href="http://LEARNINGS.md"><code>LEARNINGS.md</code></a> — captura diaria de bajo rozamiento (5 min)</p>
</li>
<li><p><a href="http://IMPLEMENTATION-HISTORY.md"><code>IMPLEMENTATION-HISTORY.md</code></a> — registro de features implementadas</p>
</li>
<li><p><strong>Skills como módulos vivos</strong> — no documentos estáticos, sino módulos con ciclo de vida</p>
</li>
</ol>
<h2><strong>El artefacto central:</strong> <a href="http://LEARNINGS.md"><strong>LEARNINGS.md</strong></a></h2>
<p>Una entrada de <a href="http://LEARNINGS.md"><code>LEARNINGS.md</code></a> en un proyecto Java real tarda 5 minutos en escribir. Esos 5 minutos previenen que el mismo bug ocurra en los próximos 8 endpoints.</p>
<p><strong>Formato estándar (bajo rozamiento):</strong></p>
<pre><code class="language-markdown">## LEARNINGS.md

### 2026-07-29 — BigDecimal comparación incorrecta
**Contexto:** Revisión del PR de PedidoService.calcularTotal()
**Bug:** La IA generó `if (monto == BigDecimal.ZERO)` para validar monto vacío.
  Pasó todos los unit tests porque los tests usaban el mismo literal.
  Falló en producción con valores calculados (0.00 != 0 por referencia).

**Insight capturado:**
- Comparar BigDecimal con `==` es siempre incorrecto.
- Usar siempre `monto.compareTo(BigDecimal.ZERO) == 0` o `BigDecimal.ZERO.equals(monto)`.

**Acciones:**
- [x] Añadido a CLAUDE.md sección Anti-patrones (#8)
- [x] Actualizado skill domain-model.md con sección "Comparaciones monetarias"
- [x] Añadido test de propiedad con jqwik: comparación con valores calculados

**Resultado:** Cero bugs de comparación BigDecimal en los siguientes 6 servicios.
</code></pre>
<pre><code class="language-markdown">### 2026-07-31 — LocalDate.now() en dominio no es testeable
**Contexto:** Debugging de PedidoService.estaVencido() — tests no deterministas
**Bug:** La IA usó `LocalDate.now()` directamente en el método de dominio.
  Los tests fallaban aleatoriamente dependiendo de la fecha de ejecución.

**Insight:**
- Nunca usar `LocalDate.now()` o `Instant.now()` directamente en clases de dominio.
- Inyectar `Clock` como dependencia y usar `LocalDate.now(clock)`.
- Permite fijar el tiempo en tests: `Clock.fixed(Instant.parse("2026-01-15T00:00:00Z"), ZoneOffset.UTC)`

**Acciones:**
- [x] Añadido a CLAUDE.md Anti-patrones (#9)
- [x] Creado skill testing.md — sección "Time-dependent testing con Clock"
- [ ] Refactorizar PedidoService para inyectar Clock (backlog JIRA-789)
</code></pre>
<h2><strong>Los cuatro tipos de insight que vale la pena capturar</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/45df1286-e605-4c1d-9b98-79de208f8764.png" alt="" style="display:block;margin:0 auto" />

<h3><strong>El ejemplo del micro-retorno</strong></h3>
<p>Un bug en un parser de Spring Boot que asumió que un campo de versión era de longitud fija. La IA generó código basado en la especificación v6 sin saber que v7+ cambió el tamaño del campo.</p>
<p><strong>El problema (5 minutos de análisis):</strong></p>
<pre><code class="language-java">// Lo que generó Claude — asumió versión fija
int version = buffer.readByte();  // correcto hasta v6
// v7+ usa 2 bytes — parseó el byte de datos como parte de la versión
</code></pre>
<p><strong>La solución permanente (10 minutos de documentación):</strong></p>
<pre><code class="language-markdown">### 2026-07-15 — Campos de versión de longitud variable
**Anti-patrón:** Nunca asumir tamaño fijo de campos sin verificar la versión del protocolo.
**Regla:** Leer siempre la versión primero. Campos de longitud variable según versión
  requieren dispatch explícito: v1-6 = 1 byte, v7+ = 2 bytes (little-endian).
**Acciones:**
- [x] CLAUDE.md Anti-patrones: "Verificar versión de protocolo antes de parsear campos"
- [x] Skill creada: .claude/skills/parsing-versioning.md
</code></pre>
<p><strong>Resultado:</strong> Cero bugs de parsing de versión en los siguientes 5 parsers generados.</p>
<hr />
<h2><strong>El ciclo de disparadores: no confíes en tu memoria</strong></h2>
<p>El error más común es decir "lo documento después". Después nunca llega. La solución es reemplazar la intención por <strong>disparadores situacionales inmediatos</strong>:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/26032fe6-770f-4bfa-bbab-2da38508500e.png" alt="" style="display:block;margin:0 auto" />

<p>El mecanismo más efectivo es <strong>integrar los disparadores directamente en el PR template</strong>. El volante gira automáticamente con cada merge:</p>
<pre><code class="language-markdown">&lt;!-- .github/pull_request_template.md — sección de aprendizaje --&gt;

## Documentación del aprendizaje

- [ ] `IMPLEMENTATION-HISTORY.md` actualizado (si fue una feature significativa)
- [ ] `LEARNINGS.md` tiene una entrada (si hubo nuevos insights o bugs encontrados)
- [ ] Skills relevantes actualizados en `.claude/skills/`
- [ ] `CLAUDE.md` actualizado si hay nuevos patrones o anti-patrones
</code></pre>
<p>Cuando esta sección está en el template, el equipo la ve en cada PR. No hace falta recordar. El proceso captura el aprendizaje automáticamente.</p>
<h2><strong>Los skills como módulos vivos</strong></h2>
<p>Los skills del Pilar 1 no son documentos que se escriben una vez. Tienen un ciclo de vida:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/1c247406-0816-4f99-bb7c-955008b005f6.png" alt="" style="display:block;margin:0 auto" />

<p><strong>Ejemplos de evolución en un proyecto Java:</strong></p>
<ul>
<li><p><a href="http://spring-boot.md"><code>spring-boot.md</code></a> se divide en <a href="http://spring-boot-controllers.md"><code>spring-boot-controllers.md</code></a> y <a href="http://spring-boot-config.md"><code>spring-boot-config.md</code></a> cuando supera las 400 líneas</p>
</li>
<li><p><a href="http://javax-patterns.md"><code>javax-patterns.md</code></a> se archiva después de completar la migración a Jakarta EE</p>
</li>
<li><p><a href="http://jpa-patterns.md"><code>jpa-patterns.md</code></a> y <a href="http://hibernate-config.md"><code>hibernate-config.md</code></a> se fusionan en <a href="http://persistence.md"><code>persistence.md</code></a> cuando el equipo unifica criterios</p>
</li>
</ul>
<h2><strong>El retorno exponencial: los números reales</strong></h2>
<p>El volante produce retorno compuesto, no lineal:</p>
<table>
<thead>
<tr>
<th>Momento</th>
<th>Contexto</th>
<th>Automatización</th>
<th>Tiempo por feature</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Día 1</strong></td>
<td>200 líneas / 5 skills</td>
<td>10%</td>
<td>4 horas</td>
</tr>
<tr>
<td><strong>Mes 1</strong></td>
<td>767 líneas / 20 skills</td>
<td>40%</td>
<td>1.5 horas</td>
</tr>
<tr>
<td><strong>Mes 3</strong></td>
<td>1.200+ líneas / 51 skills</td>
<td>75%</td>
<td>30 minutos</td>
</tr>
</tbody></table>
<p>El multiplicador de 8× no viene de un modelo más caro. Viene de un contexto más rico que permite a Haiku 4.5 hacer lo que antes requería Sonnet 5, y a Sonnet 5 hacer lo que antes requería intervención humana.</p>
<hr />
<h2><strong>Las métricas del volante</strong></h2>
<p>Cuatro KPIs que miden si el sistema está aprendiendo o estancado:</p>
<table>
<thead>
<tr>
<th>Métrica</th>
<th>Target</th>
<th>Cómo medirla en Java</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Tasa de captura</strong></td>
<td>&gt;80% de sesiones documentadas</td>
<td>Entradas en <a href="http://LEARNINGS.md">LEARNINGS.md</a> / días de desarrollo activo</td>
</tr>
<tr>
<td><strong>Reducción de errores repetidos</strong></td>
<td>90% de caída en 3 meses</td>
<td>Bugs del mismo tipo en JIRA: mes 1 vs. mes 3</td>
</tr>
<tr>
<td><strong>Crecimiento del contexto</strong></td>
<td>+50 líneas/semana en los primeros 3 meses</td>
<td><code>wc -l</code> <a href="http://CLAUDE.md"><code>CLAUDE.md</code></a> + total líneas en <code>.claude/skills/</code></td>
</tr>
<tr>
<td><strong>Precisión al primer intento</strong></td>
<td>De 3-4 iteraciones a 1</td>
<td>Rondas de revisión promedio antes del merge</td>
</tr>
</tbody></table>
<hr />
<h2><strong>La rutina de mantenimiento</strong></h2>
<p>El volante no requiere grandes inversiones de tiempo. Requiere consistencia:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/08bcf470-9bb8-421e-ae2a-12c909e617ce.png" alt="" style="display:block;margin:0 auto" />

<h2><strong>Empieza hoy: tres acciones en 30 minutos</strong></h2>
<p><strong>1. Crea</strong> <a href="http://LEARNINGS.md"><code>LEARNINGS.md</code></a> <strong>en la raíz del proyecto</strong> (5 min):</p>
<pre><code class="language-markdown"># LEARNINGS.md — Registro de aprendizaje del equipo

## Formato de entrada
- **Fecha:** YYYY-MM-DD
- **Contexto:** ¿En qué estabas trabajando?
- **Insight:** ¿Qué aprendiste?
- **Acciones:** ¿Qué actualizaste? (CLAUDE.md / skill / test)
- **Resultado:** ¿Qué evitó este aprendizaje?

---
&lt;!-- Primera entrada: usa el bug más reciente que arreglaste --&gt;
</code></pre>
<p>2. Añade la sección de aprendizaje al PR template (10 min): Copia el bloque de la sección anterior a .github/pull_request_template.md. A partir de ese momento, cada PR activa el ciclo.</p>
<p>3.Añade la primera entrada basada en el último bug de Java (15 min): No esperes al próximo bug. El último que arreglaste esta semana — el NullPointerException en el servicio de pagos, la excepción de Hibernate inesperada, el test que fallaba aleatoriamente — ya tiene un insight que vale la pena capturar.</p>
<h2><strong>El cierre de la serie</strong></h2>
<p>Seis pilares. Una arquitectura de trabajo que se autorefuerza:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/bf55f63d-154d-4a13-8215-03ee5730575e.png" alt="" style="display:block;margin:0 auto" />

<p>El Pilar 6 cierra el ciclo: los aprendizajes capturados enriquecen el <a href="http://CLAUDE.md">CLAUDE.md</a> y los skills del Pilar 1, que mejoran la delegación del Pilar 2, que hacen más efectiva la verificación del Pilar 3, que fortalecen la agencia del Pilar 4, que se integran en los guardrails del Pilar 5, que generan más aprendizajes para capturar.</p>
<p>Cada bug resuelto hace al sistema más inteligente. Cada patrón documentado hace al equipo más rápido. Cada insight capturado compone.</p>
<blockquote>
<p>Haz que tu IA sea permanentemente más inteligente con cada bug resuelto y patrón descubierto. Tus prompts de sistema son un motor de aprendizaje activo, no archivos estáticos.</p>
</blockquote>
<hr />
<p><em>¿Tienes algún</em> <a href="http://LEARNINGS.md"><code>LEARNINGS.md</code></a> <em>en tu proyecto Java? ¿O esos insights viven solo en tu memoria hasta que se olvidan? El próximo bug que arregles es el mejor momento para empezar.</em></p>
<p><em>Enjoy!</em></p>
<p><em>Joe</em></p>
]]></content:encoded></item><item><title><![CDATA[Pilar 5: Velocidad a través de límites estratégicos — por qué los guardrails aceleran tu equipo Java]]></title><description><![CDATA[Línea de apertura (opcional, para el feed): Tu equipo hizo commit directo a main porque "era un cambio pequeño". Dos horas después, toda la rama de…]]></description><link>https://joedayz.hashnode.dev/pilar-5-velocidad-a-trav-s-de-l-mites-estrat-gicos-por-qu-los-guardrails-aceleran-tu-equipo-java</link><guid isPermaLink="true">https://joedayz.hashnode.dev/pilar-5-velocidad-a-trav-s-de-l-mites-estrat-gicos-por-qu-los-guardrails-aceleran-tu-equipo-java</guid><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Fri, 31 Jul 2026 18:52:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/148cdd96-89e1-440a-9e5b-d9cd577d937b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Línea de apertura (opcional, para el feed):</strong> Tu equipo hizo commit directo a main porque "era un cambio pequeño". Dos horas después, toda la rama de producción estaba rota, tres desarrolladores bloqueados y el sprint comprometido. Los guardrails no son burocracia. Son los rieles que permiten ir a 300 km/h sin descarrilar.</p>
<p><em>Parte de la serie "Los 6 pilares del desarrollo asistido por IA" — presentado en JConf Dominicana. Adaptado a proyectos Java.</em></p>
<hr />
<p>Hay una creencia que destruye más sprints que cualquier bug técnico:</p>
<blockquote>
<p>"Saltarse los pasos acelera la entrega."</p>
</blockquote>
<p>Es comprensible. Commit directo a main se siente rápido en el minuto cero. Sin PR, sin esperar el CI, sin revisión. Sensación de progreso. El código está "listo".</p>
<p>El problema no es el commit. Es lo que ocurre después.</p>
<h2><strong>La ilusión de la velocidad desestructurada</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/8dee943c-6619-4842-afcf-a87489297596.png" alt="" style="display:block;margin:0 auto" />

<p>En Java, el escenario más común tiene este patrón:</p>
<p>Un desarrollador actualiza una dependencia de Spring Boot directamente en <code>main</code>. "Solo es una actualización de versión". El cambio pasa. Ninguna prueba falla localmente. Pero la nueva versión tiene un comportamiento diferente en el autoconfigurador de Kafka. El próximo desarrollador que hace pull tiene el contexto de Spring roto. El build de CI falla. El equipo pierde dos horas investigando algo que una prueba de integración en el PR habría detectado en cuatro minutos.</p>
<p><strong>El proceso no es burocracia si previene problemas mayores.</strong></p>
<h2><strong>El ciclo de caos que nadie planea</strong></h2>
<p>Sin guardrails, el equipo cae en este ciclo de forma casi inevitable:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/6eeadc3a-d0c1-4f8a-a6a1-dc70c4f83f94.png" alt="" style="display:block;margin:0 auto" />

<p>La falla crítica no es técnica. Es de proceso. Cada vez que un bug llega a producción sin ser interceptado, el equipo paga el precio en context-switching: interrupciones que destruyen el flujo cognitivo, días completos de debugging reactivo, y bugs que se acumulan porque nadie tiene tiempo de resolver los anteriores antes de que lleguen los siguientes.</p>
<p>En equipos Java con microservicios, el costo es multiplicado: un cambio roto en el servicio de autenticación puede bloquear a tres squads diferentes que dependen de ese contrato.</p>
<h2><strong>El Pilar 5: disciplina de procesos y límites estratégicos</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/bdc6415b-d4cf-423c-8a2a-faa1675779c2.png" alt="" style="display:block;margin:0 auto" />

<p>La diferencia entre caos y disciplina no está en cuánto código produces. Está en cuánto de ese código llega a producción sin romper nada.</p>
<table>
<thead>
<tr>
<th></th>
<th>Caos (velocidad ilusoria)</th>
<th>Disciplina (velocidad real)</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Acción inicial</strong></td>
<td>Commit directo a <code>main</code></td>
<td>Flujo estructurado: PRs + tests</td>
</tr>
<tr>
<td><strong>Impacto inmediato</strong></td>
<td>0 min de overhead</td>
<td>Micro-fricción intencional: 5–15 min</td>
</tr>
<tr>
<td><strong>Impacto secundario</strong></td>
<td>Caídas de 2–8 horas por bugs</td>
<td>Intercepción temprana de fallos</td>
</tr>
<tr>
<td><strong>Resultado neto</strong></td>
<td>Deuda técnica, equipo bloqueado</td>
<td>Curva exponencial, crecimiento sostenible</td>
</tr>
</tbody></table>
<h2><strong>El ecosistema del código limpio en Java</strong></h2>
<p>Tres capas que trabajan juntas. La disciplina no es un documento estático: son reglas integradas directamente en la infraestructura del proyecto.</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/c5384197-e62c-4213-9ad0-dcf3e4bfd9bf.png" alt="" style="display:block;margin:0 auto" />

<h3><strong>Capa 1 — Reglas de branching</strong></h3>
<p>Los límites de la pista. Sin ellos, cualquier desarrollador puede enviar código sin verificar directamente a la rama principal.</p>
<p><strong>GitHub Actions — protección de</strong> <code>main</code><strong>:</strong></p>
<pre><code class="language-yaml"># .github/branch-protection.yml (configuración via GitHub API o UI)
# Reglas mínimas para main:
# - Requerir PR antes de merge
# - Requerir CI verde (build + tests)
# - Requerir 1 reviewer aprobador
# - No permitir force push
# - No permitir borrar la rama
</code></pre>
<p><strong>Naming convention en el</strong> <a href="http://CLAUDE.md"><strong>CLAUDE.md</strong></a><strong>:</strong></p>
<pre><code class="language-markdown">## Flujo de Git

Naming de ramas:
- feat/JIRA-123-descripcion-breve    (nueva funcionalidad)
- fix/JIRA-456-nombre-del-bug        (corrección)
- chore/actualizacion-dependencias   (mantenimiento)
- release/2.4.0                      (preparación de release)

NUNCA hacer commit directo a main o develop.
Todo cambio, por pequeño que sea, pasa por PR.
</code></pre>
<h3><strong>Capa 2 — Automatización CI/CD</strong></h3>
<p>Los motores de validación. El CI es el primer revisor: rápido, imparcial, sin fatiga.</p>
<p><strong>GitHub Actions para un proyecto Spring Boot con Maven:</strong></p>
<pre><code class="language-yaml"># .github/workflows/ci.yml
name: CI — Build &amp; Quality Gates

on:
  pull_request:
    branches: [ main, develop ]

jobs:
  build-and-verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Java 21
        uses: actions/setup-java@v4
        with:
          java-version: '21'
          distribution: 'temurin'

      - name: Cache Maven
        uses: actions/cache@v4
        with:
          path: ~/.m2
          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}

      # Gate 1: Compilación
      - name: Compilar
        run: mvn clean compile -q

      # Gate 2: Checkstyle (convenciones de código)
      - name: Checkstyle
        run: mvn checkstyle:check

      # Gate 3: Tests unitarios
      - name: Tests unitarios
        run: mvn test -Dgroups="unit"

      # Gate 4: Tests de integración (con Testcontainers)
      - name: Tests de integración
        run: mvn verify -Dgroups="integration"

      # Gate 5: Cobertura mínima 80%
      - name: JaCoCo coverage gate
        run: mvn jacoco:check

      # Gate 6: Vulnerabilidades en dependencias
      - name: OWASP Dependency Check
        run: mvn org.owasp:dependency-check-maven:check
        continue-on-error: false
</code></pre>
<p><strong>Configuración JaCoCo en</strong> <code>pom.xml</code><strong>:</strong></p>
<pre><code class="language-xml">&lt;plugin&gt;
    &lt;groupId&gt;org.jacoco&lt;/groupId&gt;
    &lt;artifactId&gt;jacoco-maven-plugin&lt;/artifactId&gt;
    &lt;version&gt;0.8.12&lt;/version&gt;
    &lt;executions&gt;
        &lt;execution&gt;
            &lt;id&gt;jacoco-check&lt;/id&gt;
            &lt;goals&gt;&lt;goal&gt;check&lt;/goal&gt;&lt;/goals&gt;
            &lt;configuration&gt;
                &lt;rules&gt;
                    &lt;rule&gt;
                        &lt;element&gt;BUNDLE&lt;/element&gt;
                        &lt;limits&gt;
                            &lt;limit&gt;
                                &lt;counter&gt;LINE&lt;/counter&gt;
                                &lt;value&gt;COVEREDRATIO&lt;/value&gt;
                                &lt;minimum&gt;0.80&lt;/minimum&gt;
                            &lt;/limit&gt;
                        &lt;/limits&gt;
                    &lt;/rule&gt;
                &lt;/rules&gt;
            &lt;/configuration&gt;
        &lt;/execution&gt;
    &lt;/executions&gt;
&lt;/plugin&gt;
</code></pre>
<p>Si el CI falla, el PR no puede mergearse. El guardrail es automático, sin depender de que alguien recuerde correr las pruebas.</p>
<hr />
<h3><strong>Capa 3 — Revisión humana (PRs)</strong></h3>
<p>El control de calidad final y el canal de transferencia de conocimiento. La revisión humana hace lo que la automatización no puede: evaluar decisiones de arquitectura, detectar deuda técnica implícita y mentorizar a través del código.</p>
<p><strong>PR template para proyectos Java:</strong></p>
<pre><code class="language-markdown">&lt;!-- .github/pull_request_template.md --&gt;
## ¿Qué hace este PR?
&lt;!-- Descripción breve del cambio --&gt;

## Tipo de cambio
- [ ] feat: nueva funcionalidad
- [ ] fix: corrección de bug
- [ ] refactor: mejora sin cambio de comportamiento
- [ ] chore: actualización de dependencias / config

## Checklist de calidad

### Código generado con IA
- [ ] ¿Round-trip test para DTOs nuevos o modificados?
- [ ] ¿Código usa `jakarta.*` (no `javax.*`)?
- [ ] ¿DTOs son Java records (no clases con setters)?
- [ ] ¿Usa `BigDecimal` para montos (no Double/Float)?
- [ ] ¿Haiku verificó la implementación contra el spec OpenAPI?

### Calidad general
- [ ] CI verde (build + tests + checkstyle + cobertura)
- [ ] Sin TODOs activos no documentados
- [ ] Documentación actualizada si cambió comportamiento público
- [ ] Errores nuevos registrados en CLAUDE.md (si aplica)
</code></pre>
<h2><strong>El filtro matemático del PR</strong></h2>
<p>La micro-fricción intencional del PR (5–15 minutos) es un escudo matemático para el equipo:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/78752ee0-f66f-4148-b33b-83121599deda.png" alt="" style="display:block;margin:0 auto" />

<p>La aritmética es directa:</p>
<ul>
<li><p><strong>Sin PR:</strong> 0 minutos ahora + 2–8 horas de war room después</p>
</li>
<li><p><strong>Con PR:</strong> 5–15 minutos ahora + 0 horas de war room</p>
</li>
</ul>
<p>Un solo incidente evitado por semana paga con creces toda la fricción del proceso del sprint.</p>
<h2><strong>Implementar los guardrails en tu proyecto Java</strong></h2>
<p>Esta semana — los tres guardrails esenciales</p>
<ol>
<li>Proteger main en GitHub/GitLab (15 minutos):</li>
</ol>
<p>Requerir PR para cualquier merge Requerir CI verde Requerir al menos 1 aprobación 2. CI mínimo viable (1–2 horas):</p>
<pre><code class="language-yaml"># Versión mínima: compila + tests + checkstyle
- run: mvn clean verify checkstyle:check
</code></pre>
<p><strong>3. PR template con checklist</strong> (30 minutos): Crea <code>.github/pull_request_</code><a href="http://template.md"><code>template.md</code></a> con el checklist de tu equipo. Una casilla visible es un recordatorio que no cuesta nada ignorar pero que cambia el comportamiento del equipo.</p>
<h3><strong>Este mes — automatizar la calidad</strong></h3>
<ul>
<li><p>Añadir JaCoCo con gate de cobertura ≥80%</p>
</li>
<li><p>Añadir SpotBugs para análisis estático de Java</p>
</li>
<li><p>Añadir OWASP Dependency Check (especialmente relevante en proyectos Spring Boot con muchas dependencias transitivas)</p>
</li>
<li><p>Integrar SonarQube o SonarCloud si el equipo lo tiene disponible</p>
</li>
</ul>
<h3><strong>Este trimestre — hacer que el proceso sea invisible</strong></h3>
<p>El objetivo final es que los guardrails sean tan fluidos que el equipo no los sienta como fricción, sino como el flujo normal. Cuando un desarrollador nuevo entra al equipo, el proceso ya está ahí: no hay que explicarlo, no hay que pedirle que lo respete, simplemente no puede no seguirlo.</p>
<pre><code class="language-markdown">## CLAUDE.md — regla de proceso (añadir)

Todo PR debe pasar el CI completo antes de solicitar revisión humana.
Si el CI falla: arreglar antes de pedir revisión (no después).

El proceso no se salta aunque el cambio sea "pequeño".
Los bugs más caros en producción vinieron de cambios que parecían pequeños.
</code></pre>
<h2><strong>La frase que lo resume</strong></h2>
<blockquote>
<p>La estructuración del flujo de trabajo no es una barrera para el código. Son los rieles que permiten al equipo ir a 300 km/h sin descarrilar.</p>
</blockquote>
<p>La velocidad desestructurada es una ilusión costosa. El equipo que hace commit directo a main "porque es más rápido" paga esa deuda con war rooms, context-switching y deuda técnica acumulada. El equipo con guardrails paga 5–15 minutos por PR y compone ese ahorro en productividad semana a semana.</p>
<p><strong>Adopta los límites. Acelera el desarrollo.</strong></p>
<h2><strong>La conexión con los otros pilares</strong></h2>
<p>El <strong>Pilar 1</strong> (<a href="http://CLAUDE.md">CLAUDE.md</a> + skills) define los patrones y anti-patrones del proyecto. El Pilar 5 los hace cumplir: el checkstyle es el <a href="http://CLAUDE.md">CLAUDE.md</a> convertido en automatización; el PR template es el checklist de verificación del Pilar 3 integrado en el proceso.</p>
<p>El <strong>Pilar 2</strong> (delegación estratégica) usa Haiku 4.5 para el 60–70% de las tareas. El PR es la barrera que garantiza que la velocidad de Haiku no produce deuda: el código generado pasa por los mismos guardrails que el código humano.</p>
<p>El <strong>Pilar 3</strong> (verificación) establece las reglas técnicas (round-trip tests, corpus real). El Pilar 5 hace que esas reglas sean parte del proceso del equipo, no opcionales.</p>
<p>Los seis pilares juntos construyen el único tipo de velocidad que escala: la que no acumula deuda mientras avanza.</p>
<hr />
<p><em>¿Tu proyecto Java tiene branch protection en</em> <code>main</code><em>? ¿El CI bloquea el merge automáticamente si falla? ¿O el proceso depende de que alguien recuerde correr las pruebas?</em></p>
<p><em>Enjoy!</em></p>
<p><em>Joe</em></p>
]]></content:encoded></item><item><title><![CDATA[Pilar 4: El Director de IA — cómo mantener tu agencia técnica sin dejar de usar IA]]></title><description><![CDATA[Línea de apertura (opcional, para el feed): Llevas seis meses usando Claude para tus decisiones de arquitectura Java. Eres más rápido. Pero ya no sabes si…]]></description><link>https://joedayz.hashnode.dev/pilar-4-el-director-de-ia-c-mo-mantener-tu-agencia-t-cnica-sin-dejar-de-usar-ia</link><guid isPermaLink="true">https://joedayz.hashnode.dev/pilar-4-el-director-de-ia-c-mo-mantener-tu-agencia-t-cnica-sin-dejar-de-usar-ia</guid><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Fri, 31 Jul 2026 18:35:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/a237a975-af66-4e30-930e-815b9820d38a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Línea de apertura (opcional, para el feed):</strong> Llevas seis meses usando Claude para tus decisiones de arquitectura Java. Eres más rápido. Pero ya no sabes si elegirías Spring Security + JWT o Keycloak sin preguntarle primero. Eso no es productividad. Es <strong>atrofia</strong>.</p>
<p><em>Parte de la serie "Los 6 pilares del desarrollo asistido por IA" — basado en el material de Thor Henning Hetland (Totto) / Ægis. Adaptado a proyectos Java.</em></p>
<hr />
<p>Hay dos formas de trabajar con IA. La mayoría de los desarrolladores elige la segunda sin darse cuenta.</p>
<p><strong>El intermediario</strong> le pregunta a Claude qué hacer y ejecuta lo que dice. Más rápido al principio. Pero seis meses después no puede tomar una decisión de arquitectura sin consultarle primero. Su experiencia se erosiona.</p>
<p><strong>El director</strong> le asigna trabajo específico a la IA, triangula perspectivas, sintetiza con su propio criterio y se hace dueño de la decisión. Más lento al principio. Pero seis meses después es más rápido <em>y</em> más experto que antes.</p>
<p>El Pilar 4 es la arquitectura cognitiva para mantenerte como director, no convertirte en intermediario.</p>
<h2><strong>La cronología de seis meses que nadie ve venir</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/0c7ceb3a-5621-42be-a289-33bdcebec31e.png" alt="" style="display:block;margin:0 auto" />

<p>El patrón es siempre el mismo:</p>
<ul>
<li><p><strong>Mes 1:</strong> "Claude es increíble. Soy mucho más rápido."</p>
</li>
<li><p><strong>Mes 3:</strong> "Me siento un poco menos seguro en mis decisiones técnicas..."</p>
</li>
<li><p><strong>Mes 6:</strong> "No puedo tomar una decisión de arquitectura sin preguntarle a Claude primero."</p>
</li>
</ul>
<p>La velocidad sube. La confianza técnica cae. Y como la velocidad es visible y la confianza no, nadie lo nota hasta que es tarde.</p>
<p>En términos Java: el desarrollador que solía poder debatir los trade-offs de Spring Security vs. Keycloak, de CQRS vs. arquitectura tradicional, de JPA vs. jOOQ... ahora simplemente pregunta y ejecuta.</p>
<h2><strong>El director vs. el intermediario</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/37738e05-b42f-45a3-8751-329e157c1595.png" alt="" style="display:block;margin:0 auto" />

<p>La diferencia no está en si usas IA. Está en <strong>cómo</strong> la usas.</p>
<p>Un ejemplo concreto en Java. Tu equipo necesita decidir si implementa CQRS en el dominio de pedidos de un e-commerce.</p>
<p><strong>El intermediario pregunta:</strong></p>
<blockquote>
<p>"¿Debo usar CQRS en mi aplicación Spring Boot?"</p>
</blockquote>
<p>Claude dice que sí, con una lista de beneficios. El desarrollador implementa CQRS.</p>
<p><strong>El director pregunta:</strong></p>
<blockquote>
<p>"Estoy evaluando CQRS para el dominio de pedidos de un e-commerce con Spring Boot 3. El volumen es de 10.000 pedidos/día, el equipo tiene 4 devs, y actualmente tenemos una sola base de datos PostgreSQL. Analiza los trade-offs: complejidad operacional, consistencia eventual, y si el volumen justifica la separación de modelos de lectura y escritura."</p>
</blockquote>
<p>Claude da una respuesta matizada. El director la contrasta con otra perspectiva, sintetiza y toma la decisión con criterio propio.</p>
<h2><strong>Lectura pasiva vs. síntesis activa</strong></h2>
<p>La misma distinción aplica a cómo procesas el output de la IA:</p>
<table>
<thead>
<tr>
<th>Lectura pasiva</th>
<th>Síntesis activa</th>
</tr>
</thead>
<tbody><tr>
<td>Los músculos mentales quedan sin uso</td>
<td>Escribir organiza el pensamiento</td>
</tr>
<tr>
<td>El reconocimiento de patrones se degrada</td>
<td>Comparar perspectivas exige pensamiento crítico</td>
</tr>
<tr>
<td>La toma de decisiones se subcontrata</td>
<td>Sintetizar en tus propias palabras consolida comprensión</td>
</tr>
<tr>
<td>El aprendizaje se detiene</td>
<td>La experiencia se acumula</td>
</tr>
</tbody></table>
<p>Cuando Claude te da una configuración de Spring Security para OAuth2, hay dos caminos:</p>
<p><strong>Pasivo:</strong> copias el código, lo pegas, funciona, sigues.</p>
<p><strong>Activo:</strong> lees el código, anotas qué hace cada bean, identificas las decisiones que tomó la IA (¿por qué usó <code>SessionCreationPolicy.STATELESS</code>?, ¿por qué ese orden en los filtros?), y luego lo integras porque entiendes lo que hace.</p>
<p>El segundo camino tarda 15 minutos más. En seis meses, esa diferencia es la que separa al arquitecto del que solo sabe usar Claude.</p>
<h2><strong>El modelo de triangulación: por qué una sola IA no basta</strong></h2>
<p>La certeza técnica requiere triangulación. No porque una IA sea mala, sino porque así es como los humanos procesan la certeza de forma natural.</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/688fd5e3-99f5-4728-85b7-db20c70a11f0.png" alt="" style="display:block;margin:0 auto" />

<p><strong>Ejemplo Java — elegir entre JPA y jOOQ:</strong></p>
<p>Tienes un dominio de reportes con consultas SQL complejas (múltiples JOINs, agregaciones, paginación custom). ¿Spring Data JPA o jOOQ?</p>
<p><strong>Prompt para Claude (consciente del contexto):</strong></p>
<blockquote>
<p>"El equipo tiene dominio de JPA/Hibernate 6. Tenemos un módulo de reportes con 20+ consultas de más de 5 JOINs cada una. Evalúa con detalle los trade-offs de mantener Spring Data JPA con @Query nativas vs. migrar ese módulo a jOOQ, considerando: curva de aprendizaje, tipado en tiempo de compilación, mantenibilidad de las queries, y coste de migración."</p>
</blockquote>
<p><strong>Prompt para ChatGPT (crítica desde primeros principios):</strong></p>
<blockquote>
<p>"Asume que estoy inclinado hacia Spring Data JPA por inercia del equipo. Dame el mejor argumento posible para que un equipo Spring Boot cambie a jOOQ en un módulo de reportes con consultas complejas. Sé directo sobre los puntos donde JPA realmente falla."</p>
</blockquote>
<p>Después identificas dónde coinciden (seguramente: jOOQ tiene mejor control sobre SQL complejo), dónde difieren (quizás en la estimación del coste de migración), y escribes tu síntesis. Esa síntesis es la decisión que puedes defender ante el equipo.</p>
<hr />
<h2><strong>El bucle de 15 minutos</strong></h2>
<p>Para decisiones técnicas importantes, este es el protocolo:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/6d7eca3f-ad69-4484-b386-bf035b623ba1.png" alt="" style="display:block;margin:0 auto" />

<p>15 minutos invertidos en una decisión de arquitectura previenen horas — a veces días — de incertidumbre y rework.</p>
<p><strong>Escenario real (ficticio pero típico):</strong> Tu equipo discute si implementar Outbox Pattern para garantizar consistencia entre la base de datos PostgreSQL y Kafka en el módulo de pedidos.</p>
<p>Sin el bucle: alguien pregunta a Claude, Claude dice que sí, se implementa, tres semanas después aparecen edge cases que Claude no mencionó porque nadie preguntó de forma específica.</p>
<p>Con el bucle: formulas la pregunta con contexto real (volumen, equipo, stack), obtienes dos perspectivas, identificas el punto de fricción (complejidad operacional del Debezium vs. solución custom), escribes la síntesis, documentas la decisión en un ADR. Tres semanas después, cuando aparecen los edge cases, el ADR ya los anticipaba.</p>
<h2><strong>Las reglas del director para Java devs</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/c0ebdbbc-0627-45a3-825e-84423894415b.png" alt="" style="display:block;margin:0 auto" />

<p>La distinción clave en el día a día Java:</p>
<p><strong>Uso correcto del director (decisión de autenticación):</strong></p>
<blockquote>
<p>"Estoy diseñando la capa de autenticación para una API Spring Boot 3 con 50.000 usuarios activos. Compara JWT stateless con sesiones gestionadas por Spring Session + Redis: latencia, revocación de tokens, complejidad de implementación y escalabilidad horizontal. El equipo ya conoce Spring Security."</p>
</blockquote>
<p><strong>Uso del intermediario (evitar):</strong></p>
<blockquote>
<p>"¿Cómo implemento autenticación con Spring Boot?"</p>
</blockquote>
<p>El primero produce una respuesta accionable que puedes evaluar. El segundo produce una respuesta genérica que ejecutas sin criterio.</p>
<h2><strong>Integrar el rol de director en tu flujo Java</strong></h2>
<p><strong>En decisiones de arquitectura (antes de empezar):</strong></p>
<ul>
<li><p>Siempre formula la pregunta con contexto: equipo, volumen, stack, restricciones</p>
</li>
<li><p>Siempre contrasta con al menos una perspectiva adicional</p>
</li>
<li><p>Documenta la síntesis como ADR en <code>/docs/decisions/</code></p>
</li>
</ul>
<p><strong>En code review de código generado por IA:</strong></p>
<ul>
<li><p>Lee el diff entero, no confíes en el resumen de la IA</p>
</li>
<li><p>Pregúntate: "¿Podría explicarle a un colega por qué este código hace lo que hace?"</p>
</li>
<li><p>Si no puedes, no mergeas hasta entenderlo</p>
</li>
</ul>
<p><strong>En el</strong> <a href="http://CLAUDE.md"><strong>CLAUDE.md</strong></a> <strong>del proyecto (Pilar 1):</strong></p>
<pre><code class="language-markdown">## Decisiones de arquitectura

Toda decisión técnica mayor debe:
1. Formularse con restricciones específicas (equipo, volumen, stack)
2. Contrastarse con al menos una perspectiva adicional
3. Documentarse en docs/decisions/ con el razonamiento propio

La IA propone. El equipo decide.
</code></pre>
<p><strong>En el daily o la retrospectiva:</strong> Pregunta periódicamente: "¿Hay alguna decisión técnica de las últimas dos semanas que tomamos porque Claude lo dijo, sin haberla triangulado?"</p>
<h2><strong>La elección que se hace en cada prompt</strong></h2>
<p>Cada vez que abres una conversación con Claude hay una elección implícita:</p>
<ul>
<li><p><strong>Consumo pasivo:</strong> Pregunto → Acepto → Ejecuto. Más rápido hoy. Menos capaz en seis meses.</p>
</li>
<li><p><strong>Dirección activa:</strong> Enmarco → Contrasto → Sintetizo → Decido. 15 minutos más hoy. Mejor arquitecto en seis meses.</p>
</li>
</ul>
<p>La IA no te quita la agencia. Tú se la cedes, prompt a prompt, cada vez que aceptas la primera respuesta sin leerla, cada vez que copias sin entender, cada vez que dejas que el modelo elija por ti lo que es tuyo elegir.</p>
<p>El Pilar 4 no es una restricción al uso de IA. Es la forma de asegurarte de que el uso de IA te hace más experto, no más dependiente.</p>
<hr />
<h2><strong>La conexión con los otros pilares</strong></h2>
<p>El <strong>Pilar 1</strong> (<a href="http://CLAUDE.md">CLAUDE.md</a> + skills) documenta las decisiones pasadas del equipo para que la IA no las ignore. El director actualiza ese contexto después de cada síntesis: las decisiones que tomó y el razonamiento detrás de ellas.</p>
<p>El <strong>Pilar 2</strong> (delegación estratégica) asigna el modelo correcto para cada tarea. El director sabe que Opus 5 o Fable 5 son apropiados para triangular decisiones de arquitectura, y Haiku para ejecutar patrones ya decididos.</p>
<p>El <strong>Pilar 3</strong> (verificación) asegura que el código generado es correcto. El director no solo verifica el código: verifica que entiende el código que verifica.</p>
<p>Los seis pilares juntos son una arquitectura de trabajo, no un conjunto de herramientas. El director las orquesta.</p>
<hr />
<p><em>¿Cuándo fue la última vez que tomaste una decisión de arquitectura Java triangulando dos perspectivas de IA y escribiendo tu propia síntesis? ¿O directamente ejecutaste lo que dijo Claude? Sin juicio — es una pregunta honesta para el equipo.</em></p>
<p><em>Enjoy!</em></p>
<p><em>Joe</em></p>
]]></content:encoded></item><item><title><![CDATA[Pilar 3: AI Verification Playbook — confía en la velocidad, verifica la corrección]]></title><description><![CDATA[Línea de apertura (opcional, para el feed): Claude generó el controlador REST en 20 segundos. Pasó code review. Llegó a producción. Dos días después, el…]]></description><link>https://joedayz.hashnode.dev/pilar-3-ai-verification-playbook-conf-a-en-la-velocidad-verifica-la-correcci-n</link><guid isPermaLink="true">https://joedayz.hashnode.dev/pilar-3-ai-verification-playbook-conf-a-en-la-velocidad-verifica-la-correcci-n</guid><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Fri, 31 Jul 2026 18:14:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/ffb30e49-044e-4093-ab6f-49d50a5844d7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Línea de apertura (opcional, para el feed):</strong> Claude generó el controlador REST en 20 segundos. Pasó code review. Llegó a producción. Dos días después, el campo <code>monto</code> devolvía la ciudad del cliente. Aquí está el playbook de verificación sistemática que lo habría atrapado en 30 segundos.</p>
<p><em>Parte de la serie "Los 6 pilares del desarrollo asistido por IA" — basado en el material de Thor Henning Hetland (Totto) / Ægis. Adaptado a proyectos Java.</em></p>
<hr />
<p>El Pilar 1 le da contexto al modelo. El Pilar 2 elige el modelo correcto para cada tarea. El Pilar 3 responde la pregunta que los dos anteriores no pueden responder por sí solos:</p>
<p><strong>¿Y si el código se ve perfecto… pero está mal?</strong></p>
<p>La IA genera rápido. Eso no está en discusión. El problema es que también alucina con confianza: inventa campos, desalinea DTOs, implementa la lógica que "tiene sentido" en lugar de la que dice la especificación. Y lo hace con el mismo estilo limpio y bien formateado que el código correcto.</p>
<p>La verificación sistemática no es desconfianza en la IA. Es el cinturón de seguridad: no lo usas porque desconfíes del conductor, lo usas porque el mundo tiene variables que ningún conductor controla.</p>
<h2><strong>El costo de no verificar</strong></h2>
<p>Antes de ver las técnicas, la economía del problema:</p>
<table>
<thead>
<tr>
<th>Enfoque</th>
<th>Tiempo</th>
<th>Costo</th>
<th>Bugs detectados</th>
</tr>
</thead>
<tbody><tr>
<td>Sin verificación</td>
<td>0 min</td>
<td>$0</td>
<td>0 (hasta que explota)</td>
</tr>
<tr>
<td>Revisión manual de PR</td>
<td>30 min</td>
<td>~$50</td>
<td>~60%</td>
</tr>
<tr>
<td>Verificación sistemática</td>
<td>5 min</td>
<td>~$0.10</td>
<td>~95%</td>
</tr>
<tr>
<td>War room en producción</td>
<td>2–8 h</td>
<td>$200–$800+</td>
<td>100%… <em>después del daño</em></td>
</tr>
</tbody></table>
<p>La regla que vale la pena memorizar:</p>
<blockquote>
<p><strong>Si verificar tarda más que reimplementar, lo estás haciendo mal.</strong></p>
</blockquote>
<p>5 minutos de verificación sistemática evitan 2 a 8 horas de war room. El ROI es de 10× a 50× en tiempo, y mucho más en reputación y confianza del equipo.</p>
<h2><strong>El toolkit de 6 estrategias</strong></h2>
<p>No es una herramienta mágica. Son seis técnicas complementarias. Ninguna alucinación sobrevive a una verificación sistemática que combina las correctas para cada contexto.</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/834339d3-1010-42e4-8e81-330344ccb29d.png" alt="" style="display:block;margin:0 auto" />

<h2><strong>Estrategia 1 — Round-trip: la invariante más barata</strong></h2>
<p><strong>Configuración:</strong> 5 minutos · <strong>Costo:</strong> cercano a cero</p>
<p>La idea es deceptivamente simple: lo que entra debe salir igual. Si parseas un objeto, lo serializas de vuelta y lo vuelves a parsear, el resultado debe ser idéntico al original. Si no lo es, la IA inventó o perdió algo.</p>
<p>En Java, el caso más común es la serialización JSON con Jackson. Cuando Claude genera un nuevo DTO o modifica uno existente, esta prueba lo atrapa en 30 segundos:</p>
<pre><code class="language-java">// PedidoRoundTripTest.java
@SpringBootTest
class PedidoRoundTripTest {

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    void roundTrip_PedidoDTO_preservaTodosLosCampos() throws Exception {
        PedidoDTO original = PedidoDTO.builder()
            .id(1L)
            .numero("PED-2024-001")
            .monto(new BigDecimal("1250.75"))
            .estado(EstadoPedido.CONFIRMADO)
            .clienteId(42L)
            .build();

        // Claude generó la serialización: ¿inventó un campo? ¿perdió uno?
        String json = objectMapper.writeValueAsString(original);
        PedidoDTO restaurado = objectMapper.readValue(json, PedidoDTO.class);

        assertEquals(original, restaurado,
            "El round-trip JSON debe preservar todos los campos sin excepción");
    }

    @Test
    void roundTrip_PedidoDTO_conCamposOpcionales() throws Exception {
        // Probar con nulls — la IA a veces "adivina" valores por defecto
        PedidoDTO conNulos = PedidoDTO.builder()
            .id(2L)
            .numero("PED-2024-002")
            .monto(new BigDecimal("0.01"))
            .estado(EstadoPedido.PENDIENTE)
            .clienteId(null)  // campo opcional
            .build();

        String json = objectMapper.writeValueAsString(conNulos);
        PedidoDTO restaurado = objectMapper.readValue(json, PedidoDTO.class);

        assertEquals(conNulos, restaurado);
        assertNull(restaurado.getClienteId());
    }
}
</code></pre>
<p>Para operaciones bidireccionales (por ejemplo, exportar e importar datos entre sistemas), el round-trip se extiende a dos niveles:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/4a6342c6-622a-4cbf-95e9-e0326458c0b9.png" alt="" style="display:block;margin:0 auto" />

<p><strong>Lo que detecta en proyectos Java reales:</strong></p>
<ul>
<li><p><code>@JsonProperty</code> con nombre incorrecto (la IA usa el nombre del campo Java, no el del contrato)</p>
</li>
<li><p>Campos añadidos que no están en la especificación OpenAPI</p>
</li>
<li><p><code>BigDecimal</code> convertido a <code>Double</code> silenciosamente (pérdida de precisión en montos)</p>
</li>
<li><p><code>LocalDateTime</code> sin <code>@JsonFormat</code> — diferente representación en cada JVM</p>
</li>
</ul>
<h2><strong>Estrategia 2 — Propiedades: prueba la regla, no el ejemplo</strong></h2>
<p><strong>Configuración:</strong> moderada · <strong>Costo:</strong> $0</p>
<p>Los unit tests clásicos prueban casos específicos. La IA es muy buena generando tests que ella misma pasa. Las pruebas de propiedades son distintas: definen una regla que debe cumplirse para <strong>cualquier</strong> input posible, no solo para los tres ejemplos que el modelo eligió.</p>
<p>En Java el motor más directo es <a href="https://jqwik.net/">jqwik</a>, que funciona sobre JUnit 5:</p>
<pre><code class="language-xml">&lt;!-- pom.xml --&gt;
&lt;dependency&gt;
    &lt;groupId&gt;net.jqwik&lt;/groupId&gt;
    &lt;artifactId&gt;jqwik&lt;/artifactId&gt;
    &lt;version&gt;1.9.2&lt;/version&gt;
    &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
</code></pre>
<pre><code class="language-java">// PedidoPropiedadesTest.java
import net.jqwik.api.*;
import net.jqwik.api.constraints.*;

class PedidoPropiedadesTest {

    // Propiedad 1: el monto nunca puede ser negativo
    @Property
    void monto_siempreNoNegativo(
            @ForAll @BigRange(min = "0", max = "999999.99") BigDecimal monto) {

        PedidoDTO pedido = new PedidoDTO(1L, "TEST-001", monto, EstadoPedido.PENDIENTE, null);

        assertTrue(pedido.getMonto().compareTo(BigDecimal.ZERO) &gt;= 0,
            "Un pedido no puede tener monto negativo: " + monto);
    }

    // Propiedad 2: round-trip para cualquier monto válido
    @Property
    void roundTrip_cualquierMontoValido(
            @ForAll @BigRange(min = "0.01", max = "999999.99") BigDecimal monto)
            throws Exception {

        PedidoDTO original = new PedidoDTO(1L, "PROP-TEST", monto, EstadoPedido.CONFIRMADO, 10L);
        ObjectMapper mapper = new ObjectMapper();

        String json = mapper.writeValueAsString(original);
        PedidoDTO restaurado = mapper.readValue(json, PedidoDTO.class);

        assertEquals(0, original.getMonto().compareTo(restaurado.getMonto()),
            "El monto no debe perder precisión en la serialización");
    }

    // Propiedad 3: no puede haber referencia a clienteId inexistente
    @Property
    void lineaPedido_clienteIdDebeTenerValorPositivoSiPresente(
            @ForAll @Positive Long clienteId) {

        PedidoDTO pedido = new PedidoDTO(1L, "PROP-002", BigDecimal.TEN,
                                         EstadoPedido.PENDIENTE, clienteId);
        assertTrue(pedido.getClienteId() &gt; 0,
            "clienteId debe ser positivo si está presente");
    }
}
</code></pre>
<p>La diferencia con los unit tests convencionales:</p>
<blockquote>
<p>"La IA es buena inventando tests que ella misma pasa. Las propiedades no le preguntan <em>un</em> caso: le preguntan <em>siempre</em>."</p>
</blockquote>
<p>Un alumno que memoriza 3 ejercicios del libro saca 100 en el examen de esos 3 ejercicios. En el examen real con miles de variaciones, se cae. Las propiedades son el examen real.</p>
<h2><strong>Estrategia 3 — El patrón Haiku verify</strong></h2>
<p><strong>Configuración:</strong> 5 minutos · <strong>Costo:</strong> $0.07 por ejecución</p>
<p>Este patrón usa Haiku 4.5 (el modelo más barato) en tres pasos en cadena para verificar lo que generó un modelo más caro:</p>
<table>
<thead>
<tr>
<th>Paso</th>
<th>Acción</th>
<th>Costo</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>Haiku 4.5 genera el código</td>
<td>$0.04</td>
</tr>
<tr>
<td>2</td>
<td>Haiku 4.5 genera las pruebas round-trip</td>
<td>$0.02</td>
</tr>
<tr>
<td>3</td>
<td>Haiku 4.5 contrasta implementación vs. especificación OpenAPI</td>
<td>$0.01</td>
</tr>
<tr>
<td>4</td>
<td>Maven / Gradle ejecuta las pruebas</td>
<td>$0.00</td>
</tr>
<tr>
<td>5</td>
<td>Revisión humana aleatoria de puntos críticos</td>
<td>3 min</td>
</tr>
</tbody></table>
<p><strong>Total: $0.07 + 3 minutos</strong> vs. revisión manual completa: $50 + 30 minutos.</p>
<p>La secuencia de prompts para un controlador Spring Boot:</p>
<pre><code class="language-text">Prompt 1 (Sonnet 5 — genera el ejemplar):
"Implementa PedidoController con los endpoints POST /pedidos y
GET /pedidos/{id} según esta especificación OpenAPI: [spec aquí].
Usa Spring Boot 3, jakarta.*, y el patrón de respuesta ApiResponse&lt;T&gt;
que ya existe en el proyecto."

Prompt 2 (Haiku 4.5 — genera pruebas):
"Dado este PedidoController [código], escribe pruebas MockMvc que
verifiquen el contrato de la API: status codes, estructura del JSON
de respuesta, y que ningún campo del DTO se pierda o cambie de nombre."

Prompt 3 (Haiku 4.5 — contrasta vs. spec):
"Compara este PedidoController [código] con esta especificación OpenAPI
[spec]. Lista cualquier discrepancia: campos extra, campos faltantes,
tipos incorrectos, o comportamientos no especificados."
</code></pre>
<p>Tú revisas los puntos críticos que señala el paso 3. El resto lo verifica la máquina.</p>
<blockquote>
<p>"Modelo barato + verificación fuerte &gt; modelo caro + fe ciega."</p>
</blockquote>
<h2><strong>Estrategia 4 — Corpus real: no uses datos de juguete</strong></h2>
<p>La debilidad de los tests con datos inventados: la IA elige los datos que mejor funcionan con su implementación. El corpus real usa archivos o registros reales de producción —anonimizados— para descubrir edge cases que nadie anticipó.</p>
<p>En proyectos Java, esto significa mantener un directorio <code>src/test/resources/corpus/</code> con muestras representativas:</p>
<pre><code class="language-plaintext">src/test/resources/corpus/
├── pedidos/
│   ├── pedido-monto-maximo.json        # monto = 999999.99
│   ├── pedido-cliente-nulo.json        # clienteId ausente
│   ├── pedido-caracteres-especiales.json  # nombres con ñ, acentos
│   ├── pedido-estado-cancelado.json    # flujo de cancelación
│   └── pedido-multiples-lineas.json    # 50+ líneas de detalle
</code></pre>
<pre><code class="language-java">// PedidoCorpusTest.java
@ParameterizedTest
@MethodSource("archivosDePedidosReales")
void corpus_cadaArchivoPasaRoundTrip(Path archivoJson) throws Exception {
    String jsonOriginal = Files.readString(archivoJson);
    PedidoDTO pedido = objectMapper.readValue(jsonOriginal, PedidoDTO.class);
    String jsonReserializado = objectMapper.writeValueAsString(pedido);
    PedidoDTO restaurado = objectMapper.readValue(jsonReserializado, PedidoDTO.class);

    assertEquals(pedido, restaurado,
        "El archivo " + archivoJson.getFileName() + " falló el round-trip");
}

static Stream&lt;Path&gt; archivosDePedidosReales() throws IOException {
    return Files.list(Path.of("src/test/resources/corpus/pedidos"));
}
</code></pre>
<p>Cinco archivos reales descubren más bugs que cien tests inventados.</p>
<h2><strong>La anatomía de una alucinación — historia real (adaptada a Java)</strong></h2>
<p>Este es el patrón que más se repite en producción y que más fácilmente pasa la revisión humana.</p>
<h3><strong>Acto 1 — El DTO de aspecto perfecto</strong></h3>
<p>Claude genera <code>PedidoDTO</code> para un endpoint de migración Spring Boot 2 → 3. El código es limpio, está bien comentado, compila sin warnings:</p>
<pre><code class="language-java">// Lo que generó Claude
public record PedidoDTO(
    Long id,
    String referencia,   // ← campo inventado por la IA
    String numero,
    BigDecimal monto,
    EstadoPedido estado
) {}
</code></pre>
<p>Pasó la revisión del PR. Pasó los tests unitarios generados por la propia IA. El test de <code>PedidoServiceTest</code> usaba exactamente los mismos campos que el DTO generado.</p>
<h3><strong>Acto 2 — La falla oculta</strong></h3>
<p>La especificación OpenAPI decía:</p>
<pre><code class="language-yaml">PedidoDTO:
  type: object
  properties:
    id:
      type: integer
    numero:
      type: string
    monto:
      type: number
    estado:
      type: string
      enum: [PENDIENTE, CONFIRMADO, CANCELADO]
</code></pre>
<p>Sin campo <code>referencia</code>. La IA lo inventó porque en el servicio adyacente existía un campo con ese nombre. El sistema compiló, los tests pasaron, el deploy fue a producción.</p>
<p><strong>En producción:</strong> el API recibía JSONs sin el campo <code>referencia</code>. Jackson lo deserializaba a <code>null</code>. Downstream, el procesador de pagos esperaba ese campo como parte del contrato interno y fallaba silenciosamente.</p>
<h3><strong>Acto 3 — Lo que lo hubiera capturado en 30 segundos</strong></h3>
<pre><code class="language-java">@Test
void roundTrip_PedidoDTO_contraCorpusReal() throws Exception {
    // Este JSON viene del corpus — formato real del cliente
    String jsonReal = """
        {
            "id": 101,
            "numero": "PED-2024-001",
            "monto": 450.00,
            "estado": "CONFIRMADO"
        }
        """;

    PedidoDTO pedido = objectMapper.readValue(jsonReal, PedidoDTO.class);
    String jsonReserializado = objectMapper.writeValueAsString(pedido);

    // Si 'referencia' es un campo requerido (no nullable),
    // la deserialización habría fallado aquí mismo.
    // Si es nullable, el round-trip habría devuelto null
    // en lugar de ausente, alertando la discrepancia.
    assertThat(jsonReserializado).doesNotContain("referencia");
}
</code></pre>
<p><strong>Capturado en 30 segundos. Previno más de 4 horas de war room.</strong></p>
<p>La pregunta que vale plantear en el próximo PR de 400 líneas generado por IA: ¿quién lo habría visto en la revisión manual un viernes a las 6 PM?</p>
<h2><strong>Incorporar la verificación al pipeline Java</strong></h2>
<p>La verificación sistemática no es responsabilidad de un desarrollador individual en cada PR. Es una política del pipeline. Así queda integrado en un proyecto Spring Boot típico:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/afa1a1c0-b655-443e-a2d7-fff8354d3a2d.png" alt="" style="display:block;margin:0 auto" />

<h3><strong>El checklist Pre-PR para código generado por IA</strong></h3>
<p>Agrégalo como comentario en el PR template de tu repositorio:</p>
<pre><code class="language-markdown">## Checklist — código generado con IA

- [ ] ¿Hay test round-trip para cada DTO nuevo o modificado?
- [ ] ¿El corpus de archivos reales cubre este componente?
- [ ] ¿Haiku verificó la implementación contra la spec OpenAPI?
- [ ] ¿El test diferencial compara el nuevo comportamiento con el anterior?
- [ ] ¿Spot-check humano de 3 min en los campos críticos (montos, IDs, estados)?
- [ ] ¿`CLAUDE.md` tiene la regla: "todo parser nuevo requiere round-trip"?
</code></pre>
<h3><strong>La línea para</strong> <a href="http://CLAUDE.md"><code>CLAUDE.md</code></a></h3>
<pre><code class="language-markdown">## Reglas de verificación (obligatorias)

Todo componente nuevo que parsee, serialice o transforme datos DEBE incluir:
1. Test round-trip con JUnit 5 + Jackson (o el serializador del proyecto)
2. Al menos un archivo del corpus real en `src/test/resources/corpus/`
3. Test de propiedades con jqwik para invariantes de negocio críticas

Si la spec OpenAPI cambia, el test Haiku verify confirma alineación antes del merge.
</code></pre>
<h2><strong>Métricas de éxito</strong></h2>
<table>
<thead>
<tr>
<th>KPI</th>
<th>Meta</th>
<th>Qué medir en Java</th>
</tr>
</thead>
<tbody><tr>
<td>Tasa de captura pre-producción</td>
<td>&gt;95%</td>
<td>Bugs de IA encontrados antes del merge / total</td>
</tr>
<tr>
<td>Tiempo de verificación</td>
<td>&lt;10% del tiempo de desarrollo</td>
<td>Si la feature tomó 2h → verificar ≤12 min</td>
</tr>
<tr>
<td>ROI</td>
<td>10×–50×</td>
<td>Tiempo evitado en war room / tiempo invertido en verificación</td>
</tr>
<tr>
<td>Falsos positivos</td>
<td>&lt;5%</td>
<td>Tests que fallan sin bug real — si molesta siempre, nadie lo usa</td>
</tr>
<tr>
<td>Bugs de IA en producción</td>
<td>Cercano a cero</td>
<td>El objetivo final</td>
</tr>
</tbody></table>
<p>Cuando llega un bug de IA a producción, la pregunta correcta no es "¿quién lo aprobó en el PR?". La pregunta es: <strong>"¿qué estrategia de verificación faltaba?"</strong>. La respuesta se convierte en una nueva regla en <a href="http://CLAUDE.md"><code>CLAUDE.md</code></a>.</p>
<h2><strong>Acciones inmediatas</strong></h2>
<h3><strong>Hoy (30 minutos)</strong></h3>
<ol>
<li><p>Identifica los 2–3 DTOs más críticos de tu proyecto Spring Boot (los que mueven dinero, estados de negocio, o integran con sistemas externos)</p>
</li>
<li><p>Escribe un test round-trip para cada uno — si ya tienes <code>@SpringBootTest</code> es cuestión de agregar el test</p>
</li>
<li><p>Agrega al <a href="http://CLAUDE.md"><code>CLAUDE.md</code></a> del proyecto: "Todo DTO nuevo requiere test round-trip"</p>
</li>
</ol>
<h3><strong>Esta semana</strong></h3>
<ol>
<li><p>Crea <code>src/test/resources/corpus/</code> con 5–10 JSONs reales anonimizados</p>
</li>
<li><p>Integra el checklist Pre-PR al template del repositorio</p>
</li>
<li><p>Implementa el patrón Haiku verify para los endpoints de mayor tráfico</p>
</li>
</ol>
<h3><strong>Este mes</strong></h3>
<ol>
<li><p>Añade jqwik para las invariantes de negocio críticas (montos, estados, referencias)</p>
</li>
<li><p>Conecta los corpus tests al CI/CD — si falla el round-trip, el pipeline no avanza</p>
</li>
<li><p>Meta: tasa de captura pre-producción &gt;95%</p>
</li>
</ol>
<hr />
<h2><strong>La ecuación que cambia la perspectiva</strong></h2>
<blockquote>
<p>"Haiku barato + verificación fuerte es matemáticamente superior a un modelo caro con fe ciega."</p>
</blockquote>
<p>La IA sin verificación es velocidad hacia el precipicio. Con el playbook de verificación, es el 10× de productividad que promete — sin pagar el precio en producción.</p>
<p>El Pilar 1 te da el contexto. El Pilar 2 te ahorra dinero. El Pilar 3 hace que los dos anteriores sean seguros de usar.</p>
<hr />
<p><em>¿Qué estrategia de verificación usas hoy en tu proyecto Java? ¿Round-trip, propiedades, algo diferente? Cuéntame en los comentarios.</em></p>
<p><em>Enjoy!</em></p>
<p><em>Joe</em></p>
]]></content:encoded></item><item><title><![CDATA[Pilar 1: El ADN del codebase — cómo darle memoria a tu agente de IA en proyectos Java]]></title><description><![CDATA[Línea de apertura (opcional, para el feed): Le pediste a Claude que generara un endpoint Spring Boot. Lo hizo con Lombok cuando tu equipo usa records, con…]]></description><link>https://joedayz.hashnode.dev/pilar-1-el-adn-del-codebase-c-mo-darle-memoria-a-tu-agente-de-ia-en-proyectos-java</link><guid isPermaLink="true">https://joedayz.hashnode.dev/pilar-1-el-adn-del-codebase-c-mo-darle-memoria-a-tu-agente-de-ia-en-proyectos-java</guid><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Fri, 31 Jul 2026 17:13:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/623df864-147a-421c-bd87-ad7fac87af86.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Línea de apertura (opcional, para el feed):</strong> Le pediste a Claude que generara un endpoint Spring Boot. Lo hizo con Lombok cuando tu equipo usa records, con <code>javax</code> cuando ya migraron a <code>jakarta</code>, y con un nombre de rama que viola las convenciones del repositorio. El problema no fue el modelo. Fue la falta de contexto.</p>
<p><em>Parte de la serie "Los 6 pilares del desarrollo asistido por IA" — basado en el material de Thor Henning Hetland (Totto) / Ægis. Adaptado a proyectos Java.</em></p>
<p>Cuando un desarrollador nuevo entra al equipo, no lo sueltas al codebase sin onboarding. Le explicas la arquitectura, le muestras los patrones que usa el equipo, le dices qué no hacer y por qué. Le enseñas las convenciones de Git, los frameworks de testing, los errores que ya se cometieron.</p>
<p>La IA necesita exactamente lo mismo.</p>
<p>Sin ese contexto, Claude adivina. Y lo hace con confianza: genera código limpio, bien formateado, que compila... y que viola tres convenciones del proyecto, usa el stack equivocado y replica un bug que ya se resolvió hace dos sprints.</p>
<p>El <strong>Pilar 1</strong> convierte a la IA en un colaborador que conoce el proyecto. No una herramienta que adivina, sino un miembro del equipo que ha leído el onboarding.</p>
<h2><strong>La arquitectura dual del contexto</strong></h2>
<p>El contexto inteligente se divide en dos capas complementarias:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/f4ec18fb-42da-44f8-ac73-71f968ad3294.png" alt="" style="display:block;margin:0 auto" />

<p><a href="http://CLAUDE.md"><code>CLAUDE.md</code></a> es la guía universal: vive en la raíz del repositorio, cubre la arquitectura global, el flujo de Git y el enfoque de testing. Es lo primero que Claude lee en cada sesión.</p>
<p><code>.claude/skills/</code> son módulos de conocimiento especializado: cada archivo cubre un dominio concreto del proyecto (entidades JPA, diseño de API, convenciones de Spring Boot). Son más cortos (100–300 líneas) y más profundos que el <a href="http://CLAUDE.md"><code>CLAUDE.md</code></a>.</p>
<h2><strong>El plano base: las 7 secciones del</strong> <a href="http://CLAUDE.md"><strong>CLAUDE.md</strong></a></h2>
<p>El archivo inicial debe tener entre 500 y 1.000 líneas. No más. No menos. Estas son las siete secciones que no pueden faltar, con ejemplos directamente aplicables a un proyecto Spring Boot:</p>
<h3><strong>1. Comandos de construcción</strong></h3>
<p>Los comandos exactos para compilar, testear y ejecutar. Sin ambigüedad.</p>
<pre><code class="language-markdown">## Comandos de construcción

# Compilar
mvn clean compile -q

# Tests unitarios (sin tests de integración)
mvn test -Dgroups="unit"

# Tests de integración (requiere Docker para Testcontainers)
mvn verify -Dgroups="integration"

# Ejecutar localmente con perfil dev
mvn spring-boot:run -Dspring-boot.run.profiles=local

# Linting + checkstyle
mvn checkstyle:check

# Generar la especificación OpenAPI
mvn spring-boot:run &amp; sleep 10 &amp;&amp; curl http://localhost:8080/v3/api-docs -o docs/openapi.json
</code></pre>
<h3><strong>2. Visión general de la arquitectura</strong></h3>
<p>200–300 palabras explicando la estructura de paquetes, las capas y las decisiones de diseño clave.</p>
<pre><code class="language-markdown">## Arquitectura

Aplicación Spring Boot 3.x con arquitectura hexagonal.

Paquetes principales:
- com.empresa.pedidos.domain       → Entidades, Value Objects, puertos
- com.empresa.pedidos.application  → Casos de uso, servicios de aplicación
- com.empresa.pedidos.infrastructure → Repositorios JPA, adaptadores HTTP, Kafka
- com.empresa.pedidos.api          → Controladores REST, DTOs, mappers

Reglas de dependencia (estrictas):
- domain NO depende de ninguna otra capa
- application depende SOLO de domain
- infrastructure y api dependen de application

Base de datos: PostgreSQL 16 via Spring Data JPA / Hibernate 6
Mensajería: Apache Kafka (Spring Kafka)
Autenticación: Spring Security + JWT
</code></pre>
<h3><strong>3. Patrones críticos — lo que SIEMPRE se hace</strong></h3>
<pre><code class="language-markdown">## Patrones críticos

1. SIEMPRE usar `java.math.BigDecimal` para montos monetarios.
   Nunca Double, Float, ni int.

2. SIEMPRE usar `jakarta.*` (no `javax.*`). El proyecto está en Spring Boot 3.

3. Los DTOs son Java records inmutables. Nunca clases con setters.
   Correcto: public record PedidoDTO(Long id, String numero, BigDecimal monto) {}

4. Los IDs de entidad son Long. Los IDs de API (expuestos) son UUID como String.

5. Todo endpoint REST devuelve ApiResponse&lt;T&gt; del proyecto.
   Nunca devolver la entidad JPA directamente.

6. SIEMPRE incluir @Operation y @Parameter de OpenAPI 3 en los controladores.

7. Los mappers entre entidad y DTO usan MapStruct (ya configurado).
</code></pre>
<h3><strong>4. Anti-patrones — lo que NUNCA se hace</strong></h3>
<pre><code class="language-markdown">## Anti-patrones

1. NUNCA usar @Autowired en campos. Usar inyección por constructor siempre.

2. NUNCA hacer consultas JPA en el controlador o el DTO.
   Las queries van en el repositorio o en el caso de uso.

3. NUNCA lanzar Exception genérica. Usar las excepciones del dominio:
   PedidoNotFoundException, MontoInvalidoException, etc.

4. NUNCA usar Optional&lt;T&gt; como parámetro de método.
   Solo como valor de retorno.

5. NUNCA hacer commit en main/develop directamente. Todo via PR.

6. NUNCA usar String para representar estados. Usar el enum EstadoPedido.

7. NUNCA usar Lombok en código nuevo. El proyecto migró a records y
   constructores explícitos. Lombok solo existe en código legado no migrado.
</code></pre>
<h3><strong>5. Flujo de Git</strong></h3>
<pre><code class="language-markdown">## Flujo de Git

Naming de ramas:
- feat/JIRA-123-descripcion-corta
- fix/JIRA-456-nombre-del-bug
- chore/actualizacion-dependencias

Commits (Conventional Commits):
- feat(pedidos): agregar endpoint de cancelación
- fix(pagos): corregir cálculo de IVA con BigDecimal
- test(pedidos): agregar round-trip test para PedidoDTO

PRs:
- Mínimo 1 reviewer de otro squad
- CI debe estar verde (tests + checkstyle + coverage ≥80%)
- El título del PR sigue el mismo formato que los commits
</code></pre>
<h3><strong>6. Requisitos de testing</strong></h3>
<pre><code class="language-markdown">## Testing

Framework: JUnit 5 + AssertJ + Mockito
Cobertura mínima: 80% en clases de dominio y aplicación

Reglas:
- Tests unitarios: sin Spring context, sin base de datos
- Tests de integración: Testcontainers (PostgreSQL + Kafka)
- Todo DTO nuevo tiene test round-trip con Jackson
- El directorio src/test/resources/corpus/ contiene 5+ JSONs reales anonimizados

Nombrado:
- PedidoServiceTest          → tests unitarios
- PedidoControllerIT         → tests de integración
- PedidoDTORoundTripTest     → tests de serialización
</code></pre>
<h3><strong>7. Errores comunes del equipo</strong></h3>
<p>Esta sección es oro puro: los bugs reales que ya ocurrieron y que la IA no debe repetir.</p>
<pre><code class="language-markdown">## Errores comunes (aprende de estos)

BUG-2024-01: Campo 'clienteId' desalineado en PedidoDTO
  Causa: La IA añadió un campo 'referencia' que no estaba en el spec OpenAPI.
  Solución aplicada: Round-trip test contra corpus real.
  Regla: Todo DTO nuevo requiere test round-trip ANTES del merge.

BUG-2024-02: Double en lugar de BigDecimal para monto
  Causa: La IA usó Double por defecto para campos numéricos.
  Detectado en: cálculo de totales con pérdida de precisión.
  Regla: Siempre BigDecimal para montos (ver Patrones Críticos #1).

BUG-2024-03: javax.persistence en Spring Boot 3
  Causa: La IA usó javax.* por ser más común en sus datos de entrenamiento.
  Regla: Siempre jakarta.* (ver Patrones Críticos #2).
</code></pre>
<h2><strong>Las 4 skills de alto impacto para empezar</strong></h2>
<p>No intentes construir 50 skills el primer día. Empieza con estas cuatro (15–30 minutos cada una):</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/6a48d1b3-367d-494c-8d9e-2cae3ef7d768.png" alt="" style="display:block;margin:0 auto" />

<p>Cada skill sigue la misma estructura:</p>
<ul>
<li><p><strong>Propósito</strong> (1 párrafo — qué resuelve este módulo)</p>
</li>
<li><p><strong>Reglas</strong> con ejemplos de ✅ Correcto vs ❌ Incorrecto</p>
</li>
<li><p><strong>Checklist de verificación</strong> al final</p>
</li>
</ul>
<h2><strong>El efecto compuesto: de 2 horas a 20 minutos</strong></h2>
<p>El contexto no es un costo puntual. Es una inversión con retorno compuesto:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/f6c778c0-1239-4cfc-8172-f463a902fbec.png" alt="" style="display:block;margin:0 auto" />

<p>Los números de proyectos reales:</p>
<ul>
<li><p><strong>90%</strong> de reducción en errores de la IA</p>
</li>
<li><p><strong>7.5 horas ahorradas</strong> en la generación de 15 parsers similares</p>
</li>
<li><p>Ciclo de revisión de PR de 2–3 días → <strong>4–6 horas</strong></p>
</li>
<li><p><strong>60–70% menos</strong> uso de modelos costosos (Haiku hace lo que antes requería Sonnet)</p>
</li>
</ul>
<h2><strong>El bucle de aprendizaje continuo</strong></h2>
<p>El contexto se vuelve más inteligente con cada ciclo de desarrollo, siempre que se actualice sistemáticamente:</p>
<img src="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/9950bc70-52a1-470b-9b60-35979a9fb017.png" alt="" style="display:block;margin:0 auto" />

<p>La regla de mantenimiento es simple: <strong>después de cada bug de IA, actualizas el contexto antes de cerrar el ticket</strong>. En menos de 15 minutos. El mismo bug no vuelve a ocurrir.</p>
<hr />
<h2><strong>Cronograma de implementación</strong></h2>
<table>
<thead>
<tr>
<th>Cuándo</th>
<th>Qué hacer</th>
<th>Tiempo</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Hoy</strong></td>
<td><a href="http://CLAUDE.md">CLAUDE.md</a> básico (7 secciones) + 5 skills iniciales</td>
<td>5h</td>
</tr>
<tr>
<td><strong>Esta semana</strong></td>
<td>Ejecutar contra tareas reales, registrar errores, actualizar contexto</td>
<td>30 min/día</td>
</tr>
<tr>
<td><strong>Este mes</strong></td>
<td>Expandir a 10–15 skills; medir tiempo por tarea</td>
<td>-</td>
</tr>
<tr>
<td><strong>Este trimestre</strong></td>
<td>30–50 skills; contexto en onboarding del equipo</td>
<td>-</td>
</tr>
</tbody></table>
<p>Para empezar hoy en un proyecto Spring Boot existente, los comandos son los de menos. Lo que cambia el juego son las secciones de Anti-patrones y Errores Comunes: ahí está el conocimiento del equipo que la IA normalmente nunca tiene.</p>
<h2><strong>Las métricas que indican que el contexto está funcionando</strong></h2>
<table>
<thead>
<tr>
<th>Métrica</th>
<th>Qué medir</th>
<th>Señal de éxito</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Precisión al primer intento</strong></td>
<td>¿Cuántos prompts necesitas antes de que el código sea usable?</td>
<td>De 3–4 iteraciones a 1</td>
</tr>
<tr>
<td><strong>Adherencia a patrones</strong></td>
<td>¿La IA sigue las convenciones sin que se las recuerdes?</td>
<td>javax.* desaparece de los PRs</td>
</tr>
<tr>
<td><strong>Repetición de errores</strong></td>
<td>¿El mismo tipo de bug aparece dos veces?</td>
<td>Bugs registrados en <a href="http://CLAUDE.md">CLAUDE.md</a> no vuelven</td>
</tr>
<tr>
<td><strong>Ahorro de tiempo</strong></td>
<td>Minutos por tarea con vs. sin contexto</td>
<td>Reducción medible en el sprint</td>
</tr>
<tr>
<td><strong>Consistencia del equipo</strong></td>
<td>¿El código de Dev A y Dev B se ve igual?</td>
<td>Menos comentarios de estilo en PRs</td>
</tr>
</tbody></table>
<hr />
<h2><strong>Por qué este pilar habilita los otros dos</strong></h2>
<p>El Pilar 2 (delegación estratégica) dice: usa Haiku 4.5 para el 60–70% de las tareas de seguir patrones. Pero Haiku sin contexto no puede seguir tus patrones: los desconoce. Con un <a href="http://CLAUDE.md"><code>CLAUDE.md</code></a> sólido y las skills del dominio, Haiku 4.5 genera código que sigue tus convenciones Java, usa el stack correcto y evita los anti-patrones conocidos del equipo.</p>
<p>El Pilar 3 (verificación) dice: todo DTO nuevo necesita round-trip test. Pero si esa regla no está en <a href="http://CLAUDE.md"><code>CLAUDE.md</code></a>, la IA no la aplica por defecto. El contexto convierte las reglas de verificación en comportamiento automático.</p>
<p>Los tres pilares se sostienen mutuamente. El Pilar 1 es la base.</p>
<hr />
<p><em>¿Tu proyecto Java ya tiene un</em> <a href="http://CLAUDE.md"><code>CLAUDE.md</code></a><em>? ¿Qué secciones tienes y cuáles te faltan? Cuéntame en los comentarios.</em></p>
<p><em>Enjoy!</em></p>
<p><em>Joe</em></p>
]]></content:encoded></item><item><title><![CDATA[Pilar 2: Delegación estratégica — el modelo correcto para cada tarea de IA]]></title><description><![CDATA["Usas el mismo modelo de Claude para todo y pagas hasta 10× de más. Aquí está el mapa de cuatro niveles que cambia la factura sin cambiar la calidad."…]]></description><link>https://joedayz.hashnode.dev/pilar-2-delegaci-n-estrat-gica-el-modelo-correcto-para-cada-tarea-de-ia</link><guid isPermaLink="true">https://joedayz.hashnode.dev/pilar-2-delegaci-n-estrat-gica-el-modelo-correcto-para-cada-tarea-de-ia</guid><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Fri, 31 Jul 2026 16:35:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/d232917e-606f-468a-aae9-697ab0a52e55.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>"Usas el mismo modelo de Claude para todo y pagas hasta 10× de más. Aquí está el mapa de cuatro niveles que cambia la factura sin cambiar la calidad."</p>
<h2><strong>El problema: todos los modelos no cuestan igual</strong></h2>
<p>Anthropic publica cuatro niveles de modelo con precios muy distintos (valores de input, julio 2026):</p>
<table>
<thead>
<tr>
<th>Modelo</th>
<th>Costo input</th>
<th>Para qué</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Haiku 4.5</strong></td>
<td>$1.00 / MTok</td>
<td>Seguir patrones, tests, docs, CRUD repetitivo</td>
</tr>
<tr>
<td><strong>Sonnet 5</strong></td>
<td>$3.00 / MTok</td>
<td>Features nuevas, debugging complejo, integración</td>
</tr>
<tr>
<td><strong>Opus 5</strong></td>
<td>$5.00 / MTok</td>
<td>Arquitectura, algoritmos novedosos, decisiones críticas</td>
</tr>
<tr>
<td><strong>Fable 5</strong></td>
<td>$10.00 / MTok</td>
<td>Agentes autónomos, razonamiento largo, workflows multi-paso</td>
</tr>
</tbody></table>
<p>La diferencia entre Haiku 4.5 y Fable 5 es de <strong>10×</strong>. Entre Haiku 4.5 y Opus 5, <strong>5×</strong>. La mayoría de los equipos manda todo a Sonnet sin pensar. Eso equivale a usar un camión de mudanzas para llevar una carta al correo: funciona, pero pagas gasolina de camión por un sobre.</p>
<p>El insight que cambia la ecuación: <strong>en tareas de seguir patrones —el 60–70% de lo que hace un equipo de software— Haiku 4.5 es tan bueno como Opus 5. El modelo no importa cuando el patrón está claro.</strong></p>
<h2><strong>Los cuatro niveles de tarea</strong></h2>
<p>No todas las tareas tienen la misma complejidad. Esta taxonomía cubre el 99% de los casos:</p>
<h3><strong>Nivel 1 — Haiku 4.5 (60–70% de las tareas)</strong></h3>
<p><strong>Pregunta clave:</strong> ¿Ya existe un ejemplo claro en el proyecto?</p>
<p>Son las tareas de <strong>seguir un patrón establecido</strong>: el test número 15 con el mismo estilo que los otros 14, otro endpoint CRUD igual al de Cliente o Producto, un parser más con la misma estructura, documentación con el mismo formato.</p>
<blockquote>
<p>"Si estás copiando un patrón, no necesitas el modelo más inteligente. Necesitas el más barato y rápido… con buen contexto."</p>
</blockquote>
<h3><strong>Nivel 2 — Sonnet 5 (25–35% de las tareas)</strong></h3>
<p><strong>Pregunta clave:</strong> ¿Hay que pensar, inventar o depurar algo nuevo?</p>
<p>Features que no existen aún, bugs raros (race conditions, integraciones), el primer ejemplar de un patrón nuevo, refactors que requieren criterio. Sonnet 5 es el motor del día a día de ingeniería real.</p>
<h3><strong>Nivel 3 — Opus 5 (5–10% de las tareas)</strong></h3>
<p><strong>Pregunta clave:</strong> ¿Se rompe el sistema si esto sale mal?</p>
<p>Diseño de arquitectura, algoritmos novedosos, decisiones de seguridad crítica, refactors de alto riesgo. Opus 5 es cirugía: preciso, caro, para cuando el diagnóstico lo justifica.</p>
<h3><strong>Nivel 4 — Fable 5 (&lt;5% de las tareas)</strong></h3>
<p><strong>Pregunta clave:</strong> ¿Requiere razonamiento sostenido en decenas de pasos, o es un agente autónomo?</p>
<p>Agentes que navegan codebases completos, análisis de arquitectura que correlaciona 50+ archivos, orquestación de workflows sin intervención humana. Fable 5 es el nuevo techo del ecosistema Claude: a $10/MTok, se reserva para cuando el problema realmente lo exige.</p>
<h2><strong>El patrón template: un ejemplar, N−1 copias baratas</strong></h2>
<p>El patrón más potente del Pilar Delegación combina dos niveles:</p>
<ol>
<li><p><strong>Sonnet 5</strong> construye la primera implementación con todos los edge cases resueltos y los tests en verde.</p>
</li>
<li><p><strong>Haiku 4.5</strong> replica las N−1 instancias restantes siguiendo ese template.</p>
</li>
</ol>
<p>El resultado: misma calidad, fracción del costo.</p>
<h3><strong>Ejemplo ilustrativo — migración de API Java</strong></h3>
<p>Imagina un proyecto <code>pedidos-api</code> en Spring Boot 2 que necesita migrar a Spring Boot 3. Doce controladores REST necesitan la misma transformación: namespace <code>javax.*</code> → <code>jakarta.*</code>, anotaciones Swagger 2 (<code>@ApiOperation</code>, <code>@ApiParam</code>) → OpenAPI 3 (<code>@Operation</code>, <code>@Parameter</code>), y tests MockMvc con los nuevos patrones.</p>
<p>El flujo con el patrón template:</p>
<ul>
<li><p>Sonnet 5 migra <code>PedidoController</code> — el más complejo — con todos los edge cases resueltos y los tests en verde. Ese archivo es la receta.</p>
</li>
<li><p>Haiku 4.5 migra los 11 controladores restantes siguiendo el mismo patrón.</p>
</li>
</ul>
<table>
<thead>
<tr>
<th>Enfoque</th>
<th>Costo estimado</th>
</tr>
</thead>
<tbody><tr>
<td>Ingenuo — todo Sonnet 5</td>
<td>$6.00 (12 × $0.50)</td>
</tr>
<tr>
<td>Patrón template (Sonnet + Haiku)</td>
<td>~$2.26 (1 × $0.50 + 11 × $0.16)</td>
</tr>
<tr>
<td>Ingenuo — todo Fable 5</td>
<td>~$20.00 (12 × $1.67)</td>
</tr>
<tr>
<td>Patrón template vs Fable 5</td>
<td>~$3.43 (1 × $1.67 + 11 × $0.16)</td>
</tr>
</tbody></table>
<p>→ <strong>~62% de ahorro vs todo Sonnet 5 · ~83% de ahorro vs todo Fable 5</strong></p>
<p>Y esto no es un caso extremo. Cualquier migración masiva tiene este patrón: la lógica de transformación es idéntica en todos los controladores, solo cambian los detalles de cada uno. El primer ejemplar resuelve el problema; los demás son ejecución de receta.</p>
<p>Multiplica eso por 300+ tests, 50+ exporters o una migración de 80 endpoints de API, y el ahorro se compone rápido.</p>
<h2><strong>El árbol de decisión (cuatro preguntas)</strong></h2>
<p>Antes de abrir el chat con Claude, hazte estas preguntas en orden:</p>
<ol>
<li><p>¿Es un agente autónomo o requiere razonamiento sostenido en decenas de pasos? → SÍ: Fable 5</p>
</li>
<li><p>¿Es una decisión arquitectónica crítica o un algoritmo novedoso? → SÍ: Opus 5</p>
</li>
<li><p>¿Requiere razonamiento complejo o resolver un problema único? → SÍ: Sonnet 5</p>
</li>
<li><p>¿Está siguiendo un patrón ya establecido en el codebase? → SÍ: Haiku 4.5</p>
</li>
</ol>
<p>¿Ninguna? → Sonnet 5 (es un patrón nuevo que aún no existe en el codebase)</p>
<p>Tres ejemplos rápidos para calibrar:</p>
<ul>
<li><p>"Escribe el endpoint CRUD de Factura igual al de Pedido" → Haiku 4.5</p>
</li>
<li><p>"Hay un deadlock intermitente en el checkout" → Sonnet 5</p>
</li>
<li><p>"Diseña cómo vamos a versionar la API pública" → Opus 5</p>
</li>
<li><p>"Construye un agente que audite todo el codebase y proponga refactors" → Fable 5</p>
</li>
</ul>
<h2><strong>Por qué este pilar no funciona sin el Pilar 1</strong></h2>
<p>Haiku 4.5 barato y rápido suena bien. El problema es que <strong>sin contexto, Haiku genera código genérico</strong>: no sigue tus patrones, usa la arquitectura equivocada, comete errores que Sonnet no cometería.</p>
<p>Con un <a href="http://CLAUDE.md"><code>CLAUDE.md</code></a> sólido y skills del proyecto, Haiku 4.5 sigue patrones documentados con precisión, usa la arquitectura correcta y evita los anti-patrones conocidos. El contexto convierte a Haiku en un junior fiable. Sin ese contexto, es un junior que adivina.</p>
<p><strong>La cadena de dependencia es directa:</strong></p>
<pre><code class="language-plaintext">Pilar 1: CLAUDE.md + skills → ADN del codebase
    → Haiku 4.5 tiene el contexto para ser fiable
    → Pilar 2: delegación estratégica funciona
</code></pre>
<h2><strong>El ejercicio práctico</strong></h2>
<p>Antes de terminar de leer este artículo, piensa en las últimas 10 cosas que le pediste a Claude:</p>
<ul>
<li><p>¿Cuántas eran seguir un patrón existente (Nivel 1)?</p>
</li>
<li><p>¿Cuántas realmente necesitaban razonamiento de Nivel 3 o 4?</p>
</li>
<li><p>¿Qué modelo usaste para cada una?</p>
</li>
<li><p>¿Cuál habría sido el costo con el modelo correcto?</p>
</li>
</ul>
<p>La mayoría de los equipos descubre que entre el 60 y el 70% de sus tareas cae en Nivel 1. El endpoint CRUD número 14. El doc de API número 5. El test que sigue exactamente el mismo patrón que los otros 20. Territorio Haiku 4.5.</p>
<h2><strong>Lo que sigue</strong></h2>
<p>Ya sabes qué modelo usar para cada tarea. La pregunta siguiente es: ¿cómo verificas que lo que generó está bien?</p>
<p>Eso es el <strong>Pilar 3 — Confía, pero verifica</strong>: los patrones de validación que hacen que la delegación sea segura, no un salto de fe.</p>
<hr />
<p><em>¿Usas Claude en tu equipo de desarrollo? ¿Qué distribución de modelos tienes hoy? Cuéntame en los comentarios o escríbeme directamente.</em></p>
<p><em>Enjoy!</em></p>
<p>Joe</p>
]]></content:encoded></item><item><title><![CDATA[Jconf Dominicana 2026]]></title><description><![CDATA[En Santiago de los Caballeros, Republica Dominicana. Volví de República Dominicana con la batería cargada… y con el corazón un poco más Java. Gracias…]]></description><link>https://joedayz.hashnode.dev/jconf-dominicana-2026</link><guid isPermaLink="true">https://joedayz.hashnode.dev/jconf-dominicana-2026</guid><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Mon, 27 Jul 2026 22:44:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/e113d776-9c16-4042-913a-eec43b88abeb.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>En Santiago de los Caballeros, Republica Dominicana.</p>
<p>Volví de República Dominicana con la batería cargada… y con el corazón un poco más Java. Gracias, JConf Dominicana.</p>
<p>Hay conferencias que te dejan slides. Otras te dejan amigos. <strong>JConf Dominicana</strong> me dejó las dos cosas… y algo más difícil de explicar: esa sensación de que, aunque llegues de otro país, <strong>ya perteneces.</strong></p>
<p><em>Cuando una foto de grupo no se siente forzada… eso ya dice mucho.</em></p>
<p>Si alguien me pregunta qué se siente, lo digo sin filtro: para mí es <strong>como mi DevNexus, pero en Latam</strong>. Y si alguna vez soñaste vivir algo muy cercano a <strong>JavaOne</strong> —charlas de verdad, cenas largas, comida local, paseo por la ciudad y una hospitalidad que no se finge—, <strong>aquí lo tienes</strong>.</p>
<p>No es marketing. Se vive.</p>
<img src="https://media.licdn.com/dms/image/v2/D4E12AQE8cYxO-mZJmQ/article-inline_image-shrink_1000_1488/B4EZ.LO8xKHsAI-/0/1784747380296?e=1786579200&amp;v=beta&amp;t=1hzAqxap13HGOPUCUaRx2p4BsHrSJ5x_ttReRmcqwX8" alt="Contenido del artículo" style="display:block;margin:0 auto" />

<p><em>El auditorio, el rojo de las butacas, la gente atenta… Java con alma.</em></p>
<h3><strong>Gracias a quienes hacen posible que esto sea magia</strong></h3>
<p>Quiero agradecer de frente a <strong>Carlos Camacho</strong>, <strong>Eudris</strong>, <strong>Brayan</strong>, <strong>Rafael</strong>, <strong>Fredi</strong>, <strong>Eliezer</strong> y a <strong>todos los organizadores y el equipo de soporte</strong>. Fueron anfitriones de los buenos: los que no solo “corren un evento”, sino que <strong>te cuidan</strong>.</p>
<p><strong>Eudris</strong>, gracias por llevarnos a Santiago — por la parada y compartir con nosotros la ida. <strong>Carlos</strong>, qué buen tío: enseñarnos la ciudad, abrirnos las puertas, hacernos sentir bienvenidos de verdad. Eso no se olvida.</p>
<p>Y al equipo que estaba en el lobby con las camisetas de la <strong>Dominicana JUG</strong>, con los badges listos, con la sonrisa puesta aunque el día fuera largo… <strong>ustedes son el corazón del evento</strong>.</p>
<img src="https://media.licdn.com/dms/image/v2/D4E12AQHh-X84sdn8Aw/article-inline_image-shrink_1500_2232/B4EZ.LMQ7aK4AQ-/0/1784746676215?e=1786579200&amp;v=beta&amp;t=2S65DL6AyqO-AiLo1e_k_v6L-GM4pslHsT5tUBKRSWg" alt="Contenido del artículo" style="display:block;margin:0 auto" />

<p><em>“La comunidad de usuarios Java de República Dominicana” no es un slogan. Se ve en el pasillo.</em></p>
<img src="https://media.licdn.com/dms/image/v2/D4E12AQH5VZOb0_u4vA/article-inline_image-shrink_1000_1488/B4EZ.LMWEqK4AI-/0/1784746697427?e=1786579200&amp;v=beta&amp;t=IUiQJnC-g3ama_ABSv8hT-g8I-M5MtqCiieVyk1zeZk" alt="Contenido del artículo" style="display:block;margin:0 auto" />

<p><em>Ese ir y venir entre charlas… energía pura de comunidad.</em></p>
<h3><strong>Lo que pasa fuera del escenario</strong></h3>
<p>Las mejores conversaciones no siempre caben en 45 minutos con Q&amp;A.</p>
<p>Hubo cenas, brindis, risas, terraza de noche con la ciudad iluminada de fondo… y esa sensación de “esto es lo que vine a buscar” aunque no lo hubieras puesto en la agenda.</p>
<img src="https://media.licdn.com/dms/image/v2/D4E12AQHiQJX9G_YFiw/article-inline_image-shrink_1500_2232/B4EZ.LMdpRHoAQ-/0/1784746728411?e=1786579200&amp;v=beta&amp;t=qDc3yaJSE-73BmCbr8aznsaPT0R-klDgCD6FRpnWQ44" alt="Contenido del artículo" style="display:block;margin:0 auto" />

<p><em>Cuando el networking deja de ser networking y se vuelve noche de amigos.</em></p>
<img src="https://media.licdn.com/dms/image/v2/D4E12AQFU0VY8Rjv5KQ/article-inline_image-shrink_1500_2232/B4EZ.LMj_3KoAQ-/0/1784746754342?e=1786579200&amp;v=beta&amp;t=XtTAsUpw2uDM1FirC3rDTt5A5Nf-1zKFbQub-r_NY9k" alt="Contenido del artículo" style="display:block;margin:0 auto" />

<p><em>Ciudad, mesa compartida y la certeza de que Latam Java está más vivo que nunca.</em></p>
<h3><strong>Airbnb, Vicente, Chochos… y las conversas que importan</strong></h3>
<p>Esta vez tuve el honor de compartir Airbnb con <strong>Vicente</strong> y <strong>Chochos</strong>. Y qué lujo.</p>
<p>No solo “convivir”: <strong>grandes conversas</strong> y tomar Mezcal (gracias Chochos)—las que te hacen ver que, aunque vengamos de países distintos, <strong>tenemos muchísimo en común</strong>. Misma pasión por Java, mismos retos, misma ganas de construir comunidad sin ego.</p>
<p>Esos ratos valen tanto como cualquier keynote.</p>
<img src="https://media.licdn.com/dms/image/v2/D4E12AQH93AvdW_7V0w/article-inline_image-shrink_1000_1488/B4EZ.LMsTjJIAM-/0/1784746788570?e=1786579200&amp;v=beta&amp;t=zbejYPe1HxuA0FV1izFjezjnVwPEw1OLgJmqmg9uI3I" alt="Contenido del artículo" style="display:block;margin:0 auto" />

<p><em>Camisetas JConf, sol, sonrisas. Así se ve el Caribe Java (esta puede ser una gran charla jajaja).</em></p>
<p><em>Si te vas sin una foto así… ¿realmente fuiste a la Jconf?</em></p>
<img src="https://media.licdn.com/dms/image/v2/D4E12AQG4b7abRewdow/article-inline_image-shrink_1000_1488/B4EZ.LMw7RK4AI-/0/1784746807532?e=1786579200&amp;v=beta&amp;t=ynG-pof0EanNHvlMUr5flR5V6-U_k2_k31X6ierKXzc" alt="Contenido del artículo" style="display:block;margin:0 auto" />

<p>Que gusto ver a mi amigo <strong>Ronald</strong> de CostaRica que me dió una gran entrevista hace años y que esta publicada en <a href="https://open.spotify.com/episode/2et9QfYUVzOUB6cEnY0Wjk?si=LfmFK4MYS0WdT8fT7C-b6A"><strong>Spotify</strong></a>. Por fin pude abrazarlo, conocer algo de su vida privada y lo orgulloso que está de sus hijos. Gracias por compartir eso conmigo amigo, no sabes como necesitaba escuchar algo así.</p>
<p><em>Después de la charla: una visita por el centro de la ciudad. Abrazos, memes y “¿cuándo nos vemos en la próxima?”</em></p>
<img src="https://media.licdn.com/dms/image/v2/D4E12AQGynG-AvT4WcQ/article-inline_image-shrink_1000_1488/B4EZ.LM6mwIsAI-/0/1784746846911?e=1786579200&amp;v=beta&amp;t=IEOg1kOrskqfDcLWD98mweHAR6_TuKEYocJnu0ahG7U" alt="Contenido del artículo" style="display:block;margin:0 auto" />

<p><em>Pins, sol y la cara de “esto valió cada milla recorrida”.</em></p>
<h3><strong>Apuntes de Java</strong></h3>
<p>No podía dejar de mencionar a <a href="https://www.linkedin.com/in/diegosilval/"><strong>Diego Silva</strong></a> que también fue con su esposa, es de Perú, muy conocido en la comunidad cómo <a href="https://apuntesdejava.com/"><strong>Apuntes de Java</strong></a>. Nos dió una excelente charla sobre Jakarta EE y sus desarrollos alrededor de la misma. Que más peruanos se animen a participar de estas conferencias.</p>
<h3><strong>Por qué esto importa (más allá del CV)</strong></h3>
<p>En un mundo que a veces reduce todo a métricas, JConf Dominicana me recuerda algo simple:</p>
<p><strong>La comunidad no se descarga. Se construye.</strong> Con café en el lobby. Con una pregunta después de tu talk. Con alguien que te lleva a conocer la ciudad. Con un “quédate un rato más” en la mesa.</p>
<p>Si estás dudando si vale la pena cruzar el mar, el país o la agenda para ir… <strong>vale la pena</strong>. Trae ganas de aprender, sí. Pero sobre todo trae el corazón abierto.</p>
<p>Yo, por mi parte, <strong>espero volver</strong>.</p>
<p>Gracias, República Dominicana. Gracias, <strong>JConf Dominicana</strong>. Gracias a cada persona que hizo que esta edición se sintiera como casa.</p>
<p>Nos vemos en la próxima. ☕☕☕</p>
<p>Joe</p>
<p>#JConfDominicana #Java #ComunidadJava #LatamTech #DominicanaJUG #PeruJUG #JoeDayz</p>
]]></content:encoded></item><item><title><![CDATA[De 0 a 10x: Una hoja de ruta sencilla para implementar IA en tu equipo de desarrollo 🚀]]></title><description><![CDATA[La Inteligencia Artificial no hace que un equipo sea 10 veces más productivo por arte de magia. Lo que realmente marca la diferencia es el contexto que le…]]></description><link>https://joedayz.hashnode.dev/de-0-a-10x-una-hoja-de-ruta-sencilla-para-implementar-ia-en-tu-equipo-de-desarrollo</link><guid isPermaLink="true">https://joedayz.hashnode.dev/de-0-a-10x-una-hoja-de-ruta-sencilla-para-implementar-ia-en-tu-equipo-de-desarrollo</guid><category><![CDATA[joedayz]]></category><category><![CDATA[claude-code]]></category><dc:creator><![CDATA[José Díaz]]></dc:creator><pubDate>Sun, 12 Jul 2026 05:52:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64a79aba336591d2a1481aae/4b30fd37-773b-4d2d-a41e-d839eba928b3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>La Inteligencia Artificial no hace que un equipo sea 10 veces más productivo por arte de magia.</p>
<p>Lo que realmente marca la diferencia es el <strong>contexto</strong> que le das a la IA.</p>
<p>Muchos equipos prueban ChatGPT, Claude o GitHub Copilot durante unos días y luego concluyen que "no funciona tan bien". En realidad, el problema no suele ser la IA, sino la falta de información que tiene sobre el proyecto.</p>
<p>Veamos una hoja de ruta muy simple para implementarla.</p>
<h2>Paso 1: Hoy - Crea el contexto del proyecto</h2>
<p>La IA necesita entender tu aplicación antes de ayudarte.</p>
<p>Dedica unas horas a crear un archivo como <a href="http://CLAUDE.md"><strong>CLAUDE.md</strong></a>, <a href="http://AGENTS.md"><strong>AGENTS.md</strong></a> o <strong>README_</strong><a href="http://AI.md"><strong>AI.md</strong></a> con información como:</p>
<ul>
<li><p>¿Qué hace el proyecto?</p>
</li>
<li><p>¿Cómo se ejecuta?</p>
</li>
<li><p>Arquitectura general.</p>
</li>
<li><p>Convenciones de código.</p>
</li>
<li><p>Reglas para Git.</p>
</li>
<li><p>Patrones utilizados.</p>
</li>
</ul>
<p>Por ejemplo:</p>
<blockquote>
<p>Proyecto: Sistema de Ventas</p>
<p>Lenguaje: Java 21 Framework: Spring Boot Base de datos: PostgreSQL</p>
<p>Comandos:</p>
<ul>
<li><p>mvn clean install</p>
</li>
<li><p>mvn test</p>
</li>
<li><p>docker compose up</p>
</li>
</ul>
<p>Arquitectura: Controller -&gt; Service -&gt; Repository</p>
<p>Reglas:</p>
<ul>
<li><p>No usar lógica en Controllers</p>
</li>
<li><p>Todas las APIs deben tener pruebas</p>
</li>
</ul>
</blockquote>
<p>👉 Piensa en este documento como el <strong>manual de bienvenida para la IA</strong>.</p>
<h2>Paso 2: Esta semana - Enseña habilidades específicas</h2>
<p>Ahora la IA ya conoce el proyecto.</p>
<p>El siguiente paso es enseñarle <strong>cómo trabaja tu equipo</strong>.</p>
<p>Por ejemplo:</p>
<ul>
<li><p>Cómo escribir pruebas unitarias.</p>
</li>
<li><p>Cómo revisar un Pull Request.</p>
</li>
<li><p>Cómo documentar APIs.</p>
</li>
<li><p>Cómo nombrar clases.</p>
</li>
<li><p>Cómo detectar código duplicado.</p>
</li>
</ul>
<p>En lugar de repetir instrucciones cada día, las conviertes en <strong>Skills</strong> reutilizables.</p>
<p>Ejemplo:</p>
<blockquote>
<p>"Antes de aprobar un PR verifica cobertura de pruebas, manejo de excepciones y convenciones de nombres."</p>
</blockquote>
<p>La IA podrá ejecutar esta revisión automáticamente.</p>
<h2>Paso 3: Este mes - Amplía las habilidades</h2>
<p>Cuando el equipo ya domina las primeras Skills, es momento de crecer.</p>
<p>Puedes agregar habilidades para:</p>
<ul>
<li><p>Seguridad.</p>
</li>
<li><p>Performance.</p>
</li>
<li><p>Refactorización.</p>
</li>
<li><p>Arquitectura.</p>
</li>
<li><p>Migraciones.</p>
</li>
<li><p>Documentación.</p>
</li>
<li><p>Accesibilidad.</p>
</li>
</ul>
<p>Lo importante es que <strong>cada problema resuelto se convierta en conocimiento reutilizable</strong>.</p>
<p>Si hoy corregiste un bug complicado...</p>
<p>...mañana la IA ya sabrá cómo evitarlo.</p>
<h2>Paso 4: Este trimestre - La IA ya forma parte del proceso</h2>
<p>En este punto la IA deja de ser una herramienta ocasional.</p>
<p>Se integra al flujo normal de desarrollo.</p>
<p>Por ejemplo:</p>
<p>✅ Crear historias técnicas.</p>
<p>✅ Revisar Pull Requests.</p>
<p>✅ Detectar problemas de arquitectura.</p>
<p>✅ Generar documentación.</p>
<p>✅ Ayudar en refactorizaciones.</p>
<p>✅ Sugerir pruebas faltantes.</p>
<p>El conocimiento del equipo crece continuamente.</p>
<h2>¿Por qué funciona?</h2>
<p>Imagina contratar a un desarrollador nuevo.</p>
<p>El primer día no conoce:</p>
<ul>
<li><p>el negocio,</p>
</li>
<li><p>la arquitectura,</p>
</li>
<li><p>las reglas,</p>
</li>
<li><p>ni el estilo del equipo.</p>
</li>
</ul>
<p>Con la IA ocurre exactamente igual.</p>
<p>Si le proporcionas contexto, aprende mucho más rápido.</p>
<hr />
<h2>La idea más importante</h2>
<p>La mayoría piensa que el secreto está en escribir mejores <em>prompts</em>.</p>
<p>En realidad...</p>
<blockquote>
<p><strong>Los mejores resultados llegan cuando la IA tiene un buen contexto, no cuando escribimos prompts cada vez más largos.</strong></p>
</blockquote>
<p>Los prompts se olvidan.</p>
<p>El contexto permanece.</p>
<p>Y mientras más contexto acumula el equipo, mejores resultados obtiene la IA.</p>
<h2>Resumen</h2>
<p>📅 <strong>Hoy</strong></p>
<ul>
<li>Documenta tu proyecto.</li>
</ul>
<p>📅 <strong>Esta semana</strong></p>
<ul>
<li>Crea 3 a 5 Skills reutilizables.</li>
</ul>
<p>📅 <strong>Este mes</strong></p>
<ul>
<li>Amplía esas Skills a distintas áreas.</li>
</ul>
<p>📅 <strong>Este trimestre</strong></p>
<ul>
<li>Integra la IA en todo el ciclo de desarrollo.</li>
</ul>
<h2>Reflexión final</h2>
<p>La IA no reemplaza la experiencia del equipo.</p>
<p>La potencia.</p>
<p>Cada documento, cada decisión de arquitectura y cada lección aprendida alimentan un ecosistema donde la IA puede aportar cada vez más valor.</p>
<p>La verdadera ventaja competitiva no será <strong>quién use IA</strong>, sino <strong>quién construya el mejor contexto para que la IA trabaje junto a su equipo</strong>.</p>
<p>Enjoy!</p>
<p>Joe</p>
<p>EPILOGO:</p>
<p>✍️ <strong>¿Y tú?</strong> ¿Ya documentas el contexto de tus proyectos o todavía comienzas cada conversación con la IA desde cero? Déjamelo en los comentarios.</p>
]]></content:encoded></item></channel></rss>