<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="https://futurewithml.netlify.app/feed_style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="es">
    <tabi:metadata xmlns:tabi="https://github.com/welpo/tabi">
        <tabi:base_url>https:&#x2F;&#x2F;futurewithml.netlify.app</tabi:base_url>
        <tabi:separator>
            |
        </tabi:separator>
        <tabi:about_feeds>Esta es una fuente web, también conocida como fuente Atom. Suscríbete copiando la URL de la barra de direcciones en tu lector de noticias. Visita About Feeds para aprender más y empezar. Es gratis. </tabi:about_feeds>
        <tabi:visit_the_site>Visita la web</tabi:visit_the_site>
        <tabi:recent_posts>Publicaciones recientes</tabi:recent_posts>
        <tabi:last_updated_on>Actualizado el $DATE</tabi:last_updated_on>
        <tabi:default_theme></tabi:default_theme>
        <tabi:post_listing_date>date</tabi:post_listing_date>
        <tabi:current_section>Future With ML</tabi:current_section>
    </tabi:metadata><link rel="extra-stylesheet" href="https://futurewithml.netlify.app/skins/cyber.css?h=eb029a27afbc61465b52" /><title>Future With ML</title>
        <subtitle>Patrones de Diseño en Machine Learning, MLOps e Ingeniería de IA por Christian Picon Calderon</subtitle>
    <link href="https://futurewithml.netlify.app/es/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://futurewithml.netlify.app/es/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator><updated>2026-01-06T12:00:00+00:00</updated><id>https://futurewithml.netlify.app/es/atom.xml</id><entry xml:lang="es">
        <title>La Paradoja de la Herencia: Scoping de Herramientas en Sistemas Multi-Agente</title>
        <published>2026-01-06T12:00:00+00:00</published>
        <updated>2026-01-06T12:00:00+00:00</updated>
        <author>
            <name>Christian Picon Calderon</name>
        </author>
        <link rel="alternate" href="https://futurewithml.netlify.app/es/posts/claude-code-plugin-journey-part2/" type="text/html"/>
        <id>https://futurewithml.netlify.app/es/posts/claude-code-plugin-journey-part2/</id>
        
            <content type="html">&lt;h1 id=&quot;la-paradoja-de-la-herencia-scoping-de-herramientas-en-sistemas-multi-agente&quot;&gt;La Paradoja de la Herencia: Scoping de Herramientas en Sistemas Multi-Agente&lt;&#x2F;h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Esta es la Parte 2 de una serie de tres partes. Ve &lt;a href=&quot;&#x2F;posts&#x2F;claude-code-plugin-journey-part0&#x2F;&quot;&gt;Parte 0&lt;&#x2F;a&gt; para la visión general del plugin e instalación, o &lt;a href=&quot;&#x2F;posts&#x2F;claude-code-plugin-journey-part1&#x2F;&quot;&gt;Parte 1&lt;&#x2F;a&gt; para el viaje de desarrollo.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Resumen&lt;&#x2F;strong&gt;: Este artículo presenta observaciones empíricas del desarrollo de un plugin de Claude Code, revelando patrones fundamentales en el diseño de sistemas IA multi-agente. A través de sesiones de desarrollo documentadas, identificamos tres hallazgos clave: (1) los modelos de herencia implícita de herramientas fallan consistentemente en la práctica, requiriendo contratos de scope explícitos; (2) las restricciones de topología impuestas por la plataforma impulsan la emergencia de patrones arquitectónicos específicos; y (3) las convenciones de nombres se convierten en requisitos funcionales en sistemas IA. Estos hallazgos tienen implicaciones para el diseño de frameworks de agentes más allá de la plataforma específica estudiada.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;1-introduccion&quot;&gt;1. Introducción&lt;&#x2F;h2&gt;
&lt;p&gt;Las plataformas de desarrollo basadas en agentes representan un paradigma emergente en ingeniería de software, donde instancias de IA colaboran en tareas complejas a través de orquestación estructurada. Estas plataformas ofrecen mecanismos de extensión—plugins, commands, agentes—que permiten a los desarrolladores personalizar el comportamiento para dominios específicos.&lt;&#x2F;p&gt;
&lt;p&gt;Este artículo examina Claude Code como caso de estudio en diseño de frameworks de agentes. Claude Code permite a los desarrolladores construir plugins personalizados con commands (atajos invocados por usuario), agentes (instancias especializadas de Claude), skills (proveedores de contexto), hooks (manejadores de eventos), e integraciones MCP (conexiones a servicios externos).&lt;&#x2F;p&gt;
&lt;p&gt;Durante el desarrollo de &lt;code&gt;agent-team-creator&lt;&#x2F;code&gt;, un plugin para generar agentes IA específicos del proyecto, documentamos observaciones sistemáticas sobre el comportamiento de la plataforma. Estas observaciones revelan patrones relevantes para el diseño de sistemas multi-agente de manera más amplia.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;preguntas-de-investigacion&quot;&gt;Preguntas de Investigación&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;¿Cómo se comportan los modelos de herencia de herramientas en práctica versus documentación?&lt;&#x2F;li&gt;
&lt;li&gt;¿Qué patrones arquitectónicos emergen de las restricciones de topología de la plataforma?&lt;&#x2F;li&gt;
&lt;li&gt;¿Cómo influyen las convenciones de nombres en el comportamiento de agentes en sistemas IA?&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;2-analisis-de-arquitectura-de-plataforma&quot;&gt;2. Análisis de Arquitectura de Plataforma&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;2-1-taxonomia-de-tipos-de-componentes&quot;&gt;2.1 Taxonomía de Tipos de Componentes&lt;&#x2F;h3&gt;
&lt;p&gt;Los plugins de Claude Code soportan cinco tipos de extensión distintos, cada uno con diferentes mecanismos de activación y scope:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Componente&lt;&#x2F;th&gt;&lt;th&gt;Activador&lt;&#x2F;th&gt;&lt;th&gt;Invocación&lt;&#x2F;th&gt;&lt;th&gt;Scope&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Skills&lt;&#x2F;td&gt;&lt;td&gt;Auto (Claude decide)&lt;&#x2F;td&gt;&lt;td&gt;Implícita&lt;&#x2F;td&gt;&lt;td&gt;Cross-producto&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Commands&lt;&#x2F;td&gt;&lt;td&gt;Usuario (&lt;code&gt;&#x2F;sintaxis&lt;&#x2F;code&gt;)&lt;&#x2F;td&gt;&lt;td&gt;Explícita&lt;&#x2F;td&gt;&lt;td&gt;Claude Code&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Agents&lt;&#x2F;td&gt;&lt;td&gt;Spawn (herramienta Task)&lt;&#x2F;td&gt;&lt;td&gt;Explícita&#x2F;Implícita&lt;&#x2F;td&gt;&lt;td&gt;Claude Code&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Hooks&lt;&#x2F;td&gt;&lt;td&gt;Eventos&lt;&#x2F;td&gt;&lt;td&gt;Automática&lt;&#x2F;td&gt;&lt;td&gt;Claude Code&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;MCPs&lt;&#x2F;td&gt;&lt;td&gt;Llamadas a herramientas&lt;&#x2F;td&gt;&lt;td&gt;Explícita&lt;&#x2F;td&gt;&lt;td&gt;Claude Code&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;Observación Clave&lt;&#x2F;strong&gt;: Los Skills son únicos en ser cross-producto (funcionales en web UI, API, y CLI), mientras todos los otros componentes son específicos de Claude Code. Esto sugiere que diferentes modelos de herencia pueden aplicarse a diferentes tipos de componentes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-2-inventario-de-herramientas&quot;&gt;2.2 Inventario de Herramientas&lt;&#x2F;h3&gt;
&lt;p&gt;La plataforma provee 15 herramientas built-in disponibles para agentes:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Read, Write, Edit, MultiEdit (operaciones de archivo)&lt;&#x2F;li&gt;
&lt;li&gt;Glob, Grep, LS (operaciones de búsqueda)&lt;&#x2F;li&gt;
&lt;li&gt;Bash (comandos de sistema)&lt;&#x2F;li&gt;
&lt;li&gt;WebFetch, WebSearch (acceso web)&lt;&#x2F;li&gt;
&lt;li&gt;NotebookRead, NotebookEdit (soporte Jupyter)&lt;&#x2F;li&gt;
&lt;li&gt;TodoRead, TodoWrite (seguimiento de tareas)&lt;&#x2F;li&gt;
&lt;li&gt;exit_plan_mode (control de flujo de trabajo)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Adicionalmente, los servidores MCP (Model Context Protocol) proveen integraciones de servicios externos—acceso a bases de datos, conexiones API, servicios de terceros.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-3-eventos-de-ciclo-de-vida&quot;&gt;2.3 Eventos de Ciclo de Vida&lt;&#x2F;h3&gt;
&lt;p&gt;Nueve eventos de hook definen el ciclo de vida del agente:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Evento&lt;&#x2F;th&gt;&lt;th&gt;Activador&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;PreToolUse&lt;&#x2F;td&gt;&lt;td&gt;Antes de cualquier ejecución de herramienta&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PostToolUse&lt;&#x2F;td&gt;&lt;td&gt;Después de ejecución de herramienta&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;UserPromptSubmit&lt;&#x2F;td&gt;&lt;td&gt;Mensaje de usuario recibido&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Stop&lt;&#x2F;td&gt;&lt;td&gt;Completación de agente&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SubagentStop&lt;&#x2F;td&gt;&lt;td&gt;Completación de subagente&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SessionStart&lt;&#x2F;td&gt;&lt;td&gt;Inicialización de sesión&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SessionEnd&lt;&#x2F;td&gt;&lt;td&gt;Terminación de sesión&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PreCompact&lt;&#x2F;td&gt;&lt;td&gt;Antes de compactación de contexto&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Notification&lt;&#x2F;td&gt;&lt;td&gt;Notificación del sistema&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Los códigos de salida de hooks siguen convenciones Unix: 0 para éxito, 2 para errores bloqueantes (Claude procesa stderr), otros códigos para errores no bloqueantes.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;3-hallazgos-clave&quot;&gt;3. Hallazgos Clave&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;3-1-la-paradoja-de-la-herencia&quot;&gt;3.1 La Paradoja de la Herencia&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Afirmación de Documentación&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Herramientas MCP: Los subagentes pueden acceder a herramientas MCP de servidores MCP configurados. Cuando el campo tools se omite, los subagentes heredan todas las herramientas MCP disponibles para el hilo principal.”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Comportamiento Observado&lt;&#x2F;strong&gt;: Los subagentes definidos en plugins no pueden acceder a herramientas MCP bajo ninguna configuración probada.&lt;&#x2F;p&gt;
&lt;p&gt;Esta discrepancia está documentada en cuatro issues de GitHub (#13605, #15810, #14496, #7296), cada uno describiendo una manifestación diferente de fallo de herencia de scope:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Issue&lt;&#x2F;th&gt;&lt;th&gt;Modo de Fallo&lt;&#x2F;th&gt;&lt;th&gt;Contexto de Scope&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;#13605&lt;&#x2F;td&gt;&lt;td&gt;Agentes de plugin no pueden acceder a MCP&lt;&#x2F;td&gt;&lt;td&gt;Plugin vs built-in&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;#15810&lt;&#x2F;td&gt;&lt;td&gt;Subagentes no heredan MCP&lt;&#x2F;td&gt;&lt;td&gt;Jerarquía padre-hijo&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;#14496&lt;&#x2F;td&gt;&lt;td&gt;Prompts complejos rompen acceso MCP&lt;&#x2F;td&gt;&lt;td&gt;Complejidad de prompt&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;#7296&lt;&#x2F;td&gt;&lt;td&gt;Agentes lanzados con Task carecen de MCP&lt;&#x2F;td&gt;&lt;td&gt;Herencia de scope de usuario&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;Análisis&lt;&#x2F;strong&gt;: El patrón sugiere un problema arquitectónico fundamental en lugar de bugs aislados. La herencia de herramientas opera diferentemente a través de límites de scope:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Agentes built-in&lt;&#x2F;strong&gt; heredan herramientas MCP correctamente&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Agentes definidos en plugins&lt;&#x2F;strong&gt; no heredan herramientas MCP&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Agentes lanzados con Task&lt;&#x2F;strong&gt; reciben un scope fresco sin configuraciones de nivel de usuario&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;Implicación para Diseño de Frameworks&lt;&#x2F;strong&gt;: Los modelos de herencia implícita de herramientas requieren contratos explícitos en límites de scope. Asumir que las herramientas se propagan a través de jerarquías de agentes crea dependencias frágiles. Las declaraciones explícitas de herramientas en cada nivel de scope, aunque verbose, producen comportamiento predecible.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-2-restricciones-de-topologia-y-patrones-emergentes&quot;&gt;3.2 Restricciones de Topología y Patrones Emergentes&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Descubrimiento&lt;&#x2F;strong&gt;: La plataforma impone un límite de anidamiento de un solo nivel para spawn de agentes.&lt;&#x2F;p&gt;





&lt;div class=&quot;blocked-flow-container&quot; id=&quot;blocked-&quot;&gt;
    &lt;canvas class=&quot;blocked-flow-canvas&quot; aria-label=&quot;Flow diagram with blocked step&quot;&gt;&lt;&#x2F;canvas&gt;
&lt;&#x2F;div&gt;

&lt;script&gt;
(function() {
    const containerId = &#x27;blocked-&#x27;;
    const nodeNames = [&#x27;Agente&#x27;, &#x27;Subagente&#x27;];
    const blockedName = &#x27;Subsubagente&#x27;;

    function initBlockedFlow() {
        const container = document.getElementById(containerId);
        if (!container) return;

        const canvas = container.querySelector(&#x27;.blocked-flow-canvas&#x27;);
        const ctx = canvas.getContext(&#x27;2d&#x27;);

        let particles = [];
        let time = 0;
        let pulsePhase = 0;

        const colors = {
            nodes: [&#x27;#ff0080&#x27;, &#x27;#00d4ff&#x27;, &#x27;#00ff88&#x27;, &#x27;#8b5cf6&#x27;],
            blocked: &#x27;#ff4444&#x27;,
            blockedBg: &#x27;#442222&#x27;,
            particle: &#x27;#00ff88&#x27;,
            connection: &#x27;rgba(0, 212, 255, 0.4)&#x27;,
            blockedConnection: &#x27;rgba(255, 68, 68, 0.5)&#x27;,
            text: &#x27;#e0e0e4&#x27;
        };

        function resize() {
            const rect = container.getBoundingClientRect();
            canvas.width = rect.width;
            canvas.height = 180;
        }
        resize();
        window.addEventListener(&#x27;resize&#x27;, resize);

        function getNodePositions() {
            const allNodes = [...nodeNames, blockedName];
            const margin = 60;
            const spacing = (canvas.width - margin * 2) &#x2F; (allNodes.length - 1);
            const y = canvas.height &#x2F; 2;

            return allNodes.map((name, i) =&gt; ({
                label: name,
                x: margin + i * spacing,
                y: y,
                radius: 26,
                isBlocked: i === allNodes.length - 1,
                color: i &lt; nodeNames.length ? colors.nodes[i % colors.nodes.length] : colors.blockedBg
            }));
        }

        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            const nodes = getNodePositions();

            pulsePhase += 0.05;

            &#x2F;&#x2F; Draw connections
            for (let i = 0; i &lt; nodes.length - 1; i++) {
                const from = nodes[i];
                const to = nodes[i + 1];
                const isBlockedConnection = to.isBlocked;

                ctx.beginPath();
                ctx.moveTo(from.x + from.radius, from.y);
                ctx.lineTo(to.x - to.radius, to.y);

                if (isBlockedConnection) {
                    ctx.strokeStyle = colors.blockedConnection;
                    ctx.setLineDash([8, 4]);
                } else {
                    ctx.strokeStyle = colors.connection;
                    ctx.setLineDash([]);
                }
                ctx.lineWidth = 3;
                ctx.stroke();
                ctx.setLineDash([]);

                &#x2F;&#x2F; Arrow
                if (!isBlockedConnection) {
                    const midX = (from.x + to.x) &#x2F; 2;
                    ctx.fillStyle = colors.connection;
                    ctx.beginPath();
                    ctx.moveTo(midX - 5, from.y - 6);
                    ctx.lineTo(midX + 8, from.y);
                    ctx.lineTo(midX - 5, from.y + 6);
                    ctx.closePath();
                    ctx.fill();
                }
            }

            &#x2F;&#x2F; Draw &quot;BLOCKED&quot; label on the blocked connection
            const lastNormal = nodes[nodes.length - 2];
            const blocked = nodes[nodes.length - 1];
            const midX = (lastNormal.x + blocked.x) &#x2F; 2;

            ctx.save();
            ctx.fillStyle = colors.blocked;
            ctx.font = &#x27;bold 11px JetBrains Mono&#x27;;
            ctx.textAlign = &#x27;center&#x27;;

            &#x2F;&#x2F; Pulsing X
            const pulse = Math.sin(pulsePhase) * 0.3 + 1;
            ctx.font = `bold ${14 * pulse}px JetBrains Mono`;
            ctx.fillText(&#x27;❌&#x27;, midX, nodes[0].y - 20);

            ctx.font = &#x27;bold 10px JetBrains Mono&#x27;;
            ctx.fillText(&#x27;BLOCKED&#x27;, midX, nodes[0].y + 32);
            ctx.restore();

            &#x2F;&#x2F; Draw nodes
            nodes.forEach((node, i) =&gt; {
                if (node.isBlocked) {
                    &#x2F;&#x2F; Blocked node - pulsing red border
                    ctx.shadowColor = colors.blocked;
                    ctx.shadowBlur = 10 + Math.sin(pulsePhase) * 5;

                    ctx.fillStyle = node.color;
                    ctx.beginPath();
                    ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
                    ctx.fill();

                    ctx.strokeStyle = colors.blocked;
                    ctx.lineWidth = 3;
                    ctx.setLineDash([4, 4]);
                    ctx.stroke();
                    ctx.setLineDash([]);

                    ctx.shadowBlur = 0;

                    &#x2F;&#x2F; Strikethrough effect
                    ctx.strokeStyle = colors.blocked;
                    ctx.lineWidth = 2;
                    ctx.beginPath();
                    ctx.moveTo(node.x - node.radius + 5, node.y - node.radius + 5);
                    ctx.lineTo(node.x + node.radius - 5, node.y + node.radius - 5);
                    ctx.stroke();
                } else {
                    &#x2F;&#x2F; Normal node
                    ctx.shadowColor = node.color;
                    ctx.shadowBlur = 15;

                    ctx.fillStyle = node.color;
                    ctx.beginPath();
                    ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
                    ctx.fill();

                    ctx.shadowBlur = 0;

                    ctx.strokeStyle = &#x27;#00ff88&#x27;;
                    ctx.lineWidth = 2;
                    ctx.stroke();
                }

                &#x2F;&#x2F; Label
                ctx.fillStyle = node.isBlocked ? &#x27;#666&#x27; : &#x27;#0a0a0f&#x27;;
                ctx.font = &#x27;bold 10px JetBrains Mono&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.textBaseline = &#x27;middle&#x27;;

                &#x2F;&#x2F; Wrap text if needed
                const words = node.label.split(&#x2F;(?=[A-Z])&#x2F;);
                if (words.length &gt; 1 &amp;&amp; node.label.length &gt; 8) {
                    ctx.fillText(words[0], node.x, node.y - 6);
                    ctx.fillText(words.slice(1).join(&#x27;&#x27;), node.x, node.y + 6);
                } else {
                    ctx.fillText(node.label, node.x, node.y);
                }
            });

            &#x2F;&#x2F; Particles (only on valid connections)
            particles.forEach(p =&gt; {
                p.progress += p.speed;
                if (p.progress &gt;= 1) {
                    p.segmentIndex++;
                    p.progress = 0;
                    if (p.segmentIndex &gt;= nodes.length - 2) {
                        p.segmentIndex = 0;
                    }
                }

                const from = nodes[p.segmentIndex];
                const to = nodes[p.segmentIndex + 1];

                if (from &amp;&amp; to &amp;&amp; !to.isBlocked) {
                    const ease = p.progress * p.progress * (3 - 2 * p.progress);
                    const x = from.x + (to.x - from.x) * ease;
                    const y = from.y + (to.y - from.y) * ease;

                    ctx.fillStyle = colors.particle;
                    ctx.shadowColor = colors.particle;
                    ctx.shadowBlur = 10;
                    ctx.beginPath();
                    ctx.arc(x, y, 4, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.shadowBlur = 0;
                }
            });

            time++;
            requestAnimationFrame(draw);
        }

        &#x2F;&#x2F; Initialize particles
        for (let i = 0; i &lt; 2; i++) {
            particles.push({
                segmentIndex: i,
                progress: 0,
                speed: 0.015
            });
        }

        if (!window.matchMedia(&#x27;(prefers-reduced-motion: reduce)&#x27;).matches) {
            draw();
        } else {
            &#x2F;&#x2F; Static version
            const nodes = getNodePositions();
            nodes.forEach(node =&gt; {
                ctx.fillStyle = node.color;
                ctx.beginPath();
                ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
                ctx.fill();

                ctx.fillStyle = node.isBlocked ? &#x27;#666&#x27; : &#x27;#0a0a0f&#x27;;
                ctx.font = &#x27;bold 10px JetBrains Mono&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.fillText(node.label, node.x, node.y);
            });
        }
    }

    if (document.readyState === &#x27;loading&#x27;) {
        document.addEventListener(&#x27;DOMContentLoaded&#x27;, initBlockedFlow);
    } else {
        initBlockedFlow();
    }
})();
&lt;&#x2F;script&gt;

&lt;style&gt;
.blocked-flow-container {
    background: var(--bg-0);
    border: 1px solid var(--divider-color);
    border-radius: 12px;
    padding: 1rem;
    margin: 1.5rem 0;
    position: relative;
}

.blocked-flow-canvas {
    width: 100%;
    height: 180px;
    display: block;
}

@media (max-width: 768px) {
    .blocked-flow-container {
        overflow-x: auto;
    }

    .blocked-flow-canvas {
        min-width: 500px;
    }
}
&lt;&#x2F;style&gt;
&lt;p&gt;Cuando un agente intenta spawnear un subagente anidado, la plataforma retorna:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Error: Subagents cannot spawn subagents
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Justificación de Diseño (Inferida)&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Previene recursión infinita en sistemas autónomos&lt;&#x2F;li&gt;
&lt;li&gt;Mantiene consumo de recursos acotado&lt;&#x2F;li&gt;
&lt;li&gt;Asegura topología de ejecución predecible&lt;&#x2F;li&gt;
&lt;li&gt;Simplifica debugging y monitoreo&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Arquitectura Emergente: Hub-and-Spoke&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;







&lt;div class=&quot;hub-spoke-container&quot; id=&quot;hub-spok&quot;&gt;
    &lt;canvas class=&quot;hub-spoke-canvas&quot; aria-label=&quot;Hub-and-spoke agent topology visualization&quot;&gt;&lt;&#x2F;canvas&gt;
    &lt;div class=&quot;hub-spoke-info&quot;&gt;
        &lt;span class=&quot;info-label&quot;&gt;Topology&lt;&#x2F;span&gt;
        &lt;span class=&quot;info-value&quot;&gt;Hub-and-Spoke&lt;&#x2F;span&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;

&lt;script&gt;
(function() {
    const containerId = &#x27;hub-spok&#x27;;

    &#x2F;&#x2F; Decode HTML entities (Tera encodes &#x2F; as &amp;#x2F;)
    function decodeHTML(str) {
        const textarea = document.createElement(&#x27;textarea&#x27;);
        textarea.innerHTML = str;
        return textarea.value;
    }

    const hubName = decodeHTML(&#x27;Agente Principal&#x27;);
    const spokeNames = [decodeHTML(&#x27;Agente 1&#x27;), decodeHTML(&#x27;Agente 2&#x27;), decodeHTML(&#x27;Agente 3&#x27;)];
    const showUser = true;
    const showCommand = true;

    function initHubSpoke() {
        const container = document.getElementById(containerId);
        if (!container) return;

        const canvas = container.querySelector(&#x27;.hub-spoke-canvas&#x27;);
        const ctx = canvas.getContext(&#x27;2d&#x27;);

        let particles = [];
        let time = 0;

        &#x2F;&#x2F; Colors
        const colors = {
            user: &#x27;#ff0080&#x27;,
            command: &#x27;#ff8800&#x27;,
            hub: &#x27;#00d4ff&#x27;,
            spoke: &#x27;#8b5cf6&#x27;,
            particle: &#x27;#00ff88&#x27;,
            connection: &#x27;rgba(0, 212, 255, 0.3)&#x27;
        };

        function resize() {
            const rect = container.getBoundingClientRect();
            canvas.width = rect.width;
            canvas.height = 300;
        }
        resize();
        window.addEventListener(&#x27;resize&#x27;, resize);

        &#x2F;&#x2F; Get node positions
        function getNodes() {
            const centerX = canvas.width &#x2F; 2;
            const centerY = canvas.height &#x2F; 2 + 20;
            const spokeRadius = Math.min(canvas.width * 0.35, 120);

            const nodes = [];

            &#x2F;&#x2F; User node
            if (showUser) {
                nodes.push({
                    type: &#x27;user&#x27;,
                    label: &#x27;User&#x27;,
                    x: centerX,
                    y: 40,
                    radius: 20,
                    color: colors.user
                });
            }

            &#x2F;&#x2F; Command node
            if (showCommand) {
                nodes.push({
                    type: &#x27;command&#x27;,
                    label: &#x27;Command&#x27;,
                    x: centerX,
                    y: showUser ? 100 : 50,
                    radius: 22,
                    color: colors.command
                });
            }

            &#x2F;&#x2F; Hub node
            const hubY = showUser &amp;&amp; showCommand ? centerY : centerY - 30;
            nodes.push({
                type: &#x27;hub&#x27;,
                label: hubName,
                x: centerX,
                y: hubY,
                radius: 32,
                color: colors.hub
            });

            &#x2F;&#x2F; Spoke nodes
            const spokeCount = spokeNames.length;
            const angleStep = Math.PI &#x2F; (spokeCount + 1);
            const startAngle = Math.PI;

            spokeNames.forEach((name, i) =&gt; {
                const angle = startAngle - angleStep * (i + 1);
                nodes.push({
                    type: &#x27;spoke&#x27;,
                    label: name,
                    x: centerX + Math.cos(angle) * spokeRadius,
                    y: hubY + Math.sin(angle) * spokeRadius * 0.7,
                    radius: 24,
                    color: colors.spoke
                });
            });

            return nodes;
        }

        function createParticle(from, to) {
            return {
                fromX: from.x,
                fromY: from.y,
                toX: to.x,
                toY: to.y,
                progress: Math.random(),
                speed: 0.005 + Math.random() * 0.003,
                x: from.x,
                y: from.y
            };
        }

        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            const nodes = getNodes();

            const hub = nodes.find(n =&gt; n.type === &#x27;hub&#x27;);
            const spokes = nodes.filter(n =&gt; n.type === &#x27;spoke&#x27;);
            const command = nodes.find(n =&gt; n.type === &#x27;command&#x27;);
            const user = nodes.find(n =&gt; n.type === &#x27;user&#x27;);

            &#x2F;&#x2F; Draw connections
            ctx.lineWidth = 2;
            ctx.strokeStyle = colors.connection;

            &#x2F;&#x2F; User -&gt; Command
            if (user &amp;&amp; command) {
                ctx.beginPath();
                ctx.moveTo(user.x, user.y + user.radius);
                ctx.lineTo(command.x, command.y - command.radius);
                ctx.stroke();
            }

            &#x2F;&#x2F; Command -&gt; Hub
            if (command &amp;&amp; hub) {
                ctx.beginPath();
                ctx.moveTo(command.x, command.y + command.radius);
                ctx.lineTo(hub.x, hub.y - hub.radius);
                ctx.stroke();
            } else if (user &amp;&amp; hub) {
                ctx.beginPath();
                ctx.moveTo(user.x, user.y + user.radius);
                ctx.lineTo(hub.x, hub.y - hub.radius);
                ctx.stroke();
            }

            &#x2F;&#x2F; Hub -&gt; Spokes
            spokes.forEach(spoke =&gt; {
                ctx.beginPath();
                ctx.moveTo(hub.x, hub.y);
                ctx.lineTo(spoke.x, spoke.y);
                ctx.stroke();
            });

            &#x2F;&#x2F; Draw nodes
            nodes.forEach(node =&gt; {
                &#x2F;&#x2F; Glow
                const gradient = ctx.createRadialGradient(
                    node.x, node.y, 0,
                    node.x, node.y, node.radius * 2
                );
                gradient.addColorStop(0, node.color.replace(&#x27;)&#x27;, &#x27;, 0.3)&#x27;).replace(&#x27;#&#x27;, &#x27;rgba(&#x27;).replace(&#x2F;^rgba\(([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})&#x2F;, (m, r, g, b) =&gt; `rgba(${parseInt(r, 16)}, ${parseInt(g, 16)}, ${parseInt(b, 16)}`));
                gradient.addColorStop(1, &#x27;transparent&#x27;);

                &#x2F;&#x2F; Simpler glow approach
                ctx.shadowColor = node.color;
                ctx.shadowBlur = 15;

                &#x2F;&#x2F; Node circle
                ctx.fillStyle = node.color;
                ctx.beginPath();
                ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
                ctx.fill();

                ctx.shadowBlur = 0;

                &#x2F;&#x2F; Border
                ctx.strokeStyle = node.color;
                ctx.lineWidth = 2;
                ctx.stroke();

                &#x2F;&#x2F; Label
                ctx.fillStyle = &#x27;#e0e0e4&#x27;;
                ctx.font = node.type === &#x27;hub&#x27; ? &#x27;bold 11px JetBrains Mono&#x27; : &#x27;10px JetBrains Mono&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.textBaseline = &#x27;middle&#x27;;

                &#x2F;&#x2F; Wrap long labels
                const maxWidth = node.radius * 1.8;
                const words = node.label.split(&#x27; &#x27;);
                if (words.length &gt; 1 &amp;&amp; ctx.measureText(node.label).width &gt; maxWidth) {
                    ctx.fillText(words[0], node.x, node.y - 6);
                    ctx.fillText(words.slice(1).join(&#x27; &#x27;), node.x, node.y + 6);
                } else {
                    ctx.fillText(node.label, node.x, node.y);
                }

                &#x2F;&#x2F; Type indicator below node
                if (node.type === &#x27;hub&#x27;) {
                    ctx.fillStyle = &#x27;#8888a0&#x27;;
                    ctx.font = &#x27;9px JetBrains Mono&#x27;;
                    ctx.fillText(&#x27;(Hub)&#x27;, node.x, node.y + node.radius + 14);
                }
            });

            &#x2F;&#x2F; Update and draw particles
            particles.forEach(p =&gt; {
                p.progress += p.speed;
                if (p.progress &gt;= 1) {
                    p.progress = 0;
                    &#x2F;&#x2F; Reverse direction
                    [p.fromX, p.toX] = [p.toX, p.fromX];
                    [p.fromY, p.toY] = [p.toY, p.fromY];
                }

                const ease = p.progress * p.progress * (3 - 2 * p.progress);
                p.x = p.fromX + (p.toX - p.fromX) * ease;
                p.y = p.fromY + (p.toY - p.fromY) * ease;

                ctx.fillStyle = colors.particle;
                ctx.beginPath();
                ctx.arc(p.x, p.y, 3, 0, Math.PI * 2);
                ctx.fill();

                &#x2F;&#x2F; Glow
                ctx.shadowColor = colors.particle;
                ctx.shadowBlur = 10;
                ctx.beginPath();
                ctx.arc(p.x, p.y, 3, 0, Math.PI * 2);
                ctx.fill();
                ctx.shadowBlur = 0;
            });

            time++;
            requestAnimationFrame(draw);
        }

        &#x2F;&#x2F; Initialize particles
        const nodes = getNodes();
        const hub = nodes.find(n =&gt; n.type === &#x27;hub&#x27;);
        const spokes = nodes.filter(n =&gt; n.type === &#x27;spoke&#x27;);

        spokes.forEach(spoke =&gt; {
            particles.push(createParticle(hub, spoke));
        });

        &#x2F;&#x2F; Respect reduced motion
        if (!window.matchMedia(&#x27;(prefers-reduced-motion: reduce)&#x27;).matches) {
            draw();
        } else {
            &#x2F;&#x2F; Static version
            const nodes = getNodes();
            const hub = nodes.find(n =&gt; n.type === &#x27;hub&#x27;);
            const spokes = nodes.filter(n =&gt; n.type === &#x27;spoke&#x27;);
            const command = nodes.find(n =&gt; n.type === &#x27;command&#x27;);
            const user = nodes.find(n =&gt; n.type === &#x27;user&#x27;);

            ctx.lineWidth = 2;
            ctx.strokeStyle = colors.connection;

            if (user &amp;&amp; command) {
                ctx.beginPath();
                ctx.moveTo(user.x, user.y + user.radius);
                ctx.lineTo(command.x, command.y - command.radius);
                ctx.stroke();
            }

            if (command &amp;&amp; hub) {
                ctx.beginPath();
                ctx.moveTo(command.x, command.y + command.radius);
                ctx.lineTo(hub.x, hub.y - hub.radius);
                ctx.stroke();
            }

            spokes.forEach(spoke =&gt; {
                ctx.beginPath();
                ctx.moveTo(hub.x, hub.y);
                ctx.lineTo(spoke.x, spoke.y);
                ctx.stroke();
            });

            nodes.forEach(node =&gt; {
                ctx.fillStyle = node.color;
                ctx.beginPath();
                ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
                ctx.fill();

                ctx.fillStyle = &#x27;#e0e0e4&#x27;;
                ctx.font = node.type === &#x27;hub&#x27; ? &#x27;bold 11px JetBrains Mono&#x27; : &#x27;10px JetBrains Mono&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.textBaseline = &#x27;middle&#x27;;
                ctx.fillText(node.label, node.x, node.y);
            });
        }
    }

    if (document.readyState === &#x27;loading&#x27;) {
        document.addEventListener(&#x27;DOMContentLoaded&#x27;, initHubSpoke);
    } else {
        initHubSpoke();
    }
})();
&lt;&#x2F;script&gt;

&lt;style&gt;
.hub-spoke-container {
    background: var(--bg-0);
    border: 1px solid var(--divider-color);
    border-radius: 12px;
    padding: 1rem;
    margin: 1.5rem 0;
    position: relative;
}

.hub-spoke-canvas {
    width: 100%;
    height: 300px;
    display: block;
}

.hub-spoke-info {
    position: absolute;
    bottom: 1rem;
    right: 1rem;
    background: rgba(0, 0, 0, 0.6);
    padding: 0.5rem 0.75rem;
    border-radius: 6px;
    font-family: &#x27;JetBrains Mono&#x27;, monospace;
    font-size: 0.75rem;
}

.hub-spoke-info .info-label {
    color: var(--meta-color);
    display: block;
    margin-bottom: 0.25rem;
}

.hub-spoke-info .info-value {
    color: #00d4ff;
}

@media (max-width: 768px) {
    .hub-spoke-canvas {
        height: 250px;
    }
}
&lt;&#x2F;style&gt;
&lt;p&gt;Esta restricción elimina jerarquías de agentes en estructura de árbol en favor de topologías planas coordinadas por hub. El agente “hub” coordina ejecución paralela de agentes “spoke”. Ningún spoke puede spawnear agentes adicionales.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Trade-off Observado&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Capacidad Perdida&lt;&#x2F;th&gt;&lt;th&gt;Propiedad Ganada&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Descomposición recursiva&lt;&#x2F;td&gt;&lt;td&gt;Profundidad de ejecución acotada&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Jerarquía dinámica&lt;&#x2F;td&gt;&lt;td&gt;Topología predecible&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Anidamiento arbitrario&lt;&#x2F;td&gt;&lt;td&gt;Gestión de recursos simplificada&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;Implicación para Diseño de Frameworks&lt;&#x2F;strong&gt;: Las restricciones de topología son decisiones de diseño, no meras limitaciones. El patrón hub-and-spoke que emerge del anidamiento de un solo nivel produce sistemas más fáciles de razonar, depurar, y monitorear que estructuras recursivas arbitrarias.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-3-naming-como-comportamiento&quot;&gt;3.3 Naming como Comportamiento&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Descubrimiento&lt;&#x2F;strong&gt;: Claude Code infiere comportamiento de agente a partir de nombres de agentes.&lt;&#x2F;p&gt;
&lt;p&gt;Un agente llamado &lt;code&gt;code-reviewer&lt;&#x2F;code&gt; activa comportamientos de revisión built-in que pueden sobrescribir instrucciones personalizadas del system prompt. La plataforma aplica heurísticas basadas en convenciones de nombres.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Patrón Observado&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Nombre de Agente&lt;&#x2F;th&gt;&lt;th&gt;Comportamiento Inferido&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;code-reviewer&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Patrones genéricos de revisión de código&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;test-writer&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Patrones de generación de tests&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;implementation-planner&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Menos inferencia, más control personalizado&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;Análisis&lt;&#x2F;strong&gt;: Esto representa un paradigma de “convención sobre configuración” aplicado a sistemas de agentes IA. La plataforma asume que nombres semánticamente significativos llevan intención de comportamiento.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Implicaciones&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Las convenciones de nombres se convierten en requisitos funcionales&lt;&#x2F;li&gt;
&lt;li&gt;Nombres distintivos, no genéricos preservan comportamiento personalizado&lt;&#x2F;li&gt;
&lt;li&gt;El diseño de sistemas de agentes debe considerar inferencia basada en nombres&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;4-patrones-emergentes&quot;&gt;4. Patrones Emergentes&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;4-1-separacion-i-o-arquitectura-hibrida&quot;&gt;4.1 Separación I&#x2F;O (Arquitectura Híbrida)&lt;&#x2F;h3&gt;
&lt;p&gt;En respuesta a las limitaciones de acceso MCP, emergió un patrón arquitectónico claro: separar operaciones de I&#x2F;O de operaciones de inteligencia.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Modelo de Capas&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Capa&lt;&#x2F;th&gt;&lt;th&gt;Responsabilidades&lt;&#x2F;th&gt;&lt;th&gt;Componentes&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;I&#x2F;O&lt;&#x2F;td&gt;&lt;td&gt;Acceso MCP, operaciones de archivo, interacción con usuario, caché&lt;&#x2F;td&gt;&lt;td&gt;Commands&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Inteligencia&lt;&#x2F;td&gt;&lt;td&gt;Razonamiento, análisis, formateo, decisiones&lt;&#x2F;td&gt;&lt;td&gt;Agents&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;Ejemplo de Pipeline de 6 Fases&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;



&lt;div class=&quot;pipeline-container&quot; id=&quot;pipeline&quot;&gt;
    &lt;canvas class=&quot;pipeline-canvas&quot; aria-label=&quot;Pipeline flow visualization&quot;&gt;&lt;&#x2F;canvas&gt;
    &lt;div class=&quot;pipeline-legend&quot;&gt;
        &lt;span class=&quot;legend-item&quot;&gt;&lt;span class=&quot;legend-dot command&quot;&gt;&lt;&#x2F;span&gt; Command (I&#x2F;O)&lt;&#x2F;span&gt;
        &lt;span class=&quot;legend-item&quot;&gt;&lt;span class=&quot;legend-dot agent&quot;&gt;&lt;&#x2F;span&gt; Agent (Intelligence)&lt;&#x2F;span&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;

&lt;script&gt;
(function() {
    const containerId = &#x27;pipeline&#x27;;
    const phasesData = [
    {&quot;phase&quot;: 0, &quot;owner&quot;: &quot;Command&quot;, &quot;label&quot;: &quot;Disponibilidad&quot;, &quot;io&quot;: &quot;external&quot;},
    {&quot;phase&quot;: 1, &quot;owner&quot;: &quot;Command&quot;, &quot;label&quot;: &quot;Resolver Datos&quot;, &quot;io&quot;: &quot;external&quot;},
    {&quot;phase&quot;: 2, &quot;owner&quot;: &quot;Command&quot;, &quot;label&quot;: &quot;Cargar Contenido&quot;, &quot;io&quot;: &quot;local&quot;},
    {&quot;phase&quot;: 3, &quot;owner&quot;: &quot;Command&quot;, &quot;label&quot;: &quot;Validación&quot;, &quot;io&quot;: &quot;external&quot;},
    {&quot;phase&quot;: 4, &quot;owner&quot;: &quot;Agent&quot;, &quot;label&quot;: &quot;Razonamiento&quot;, &quot;io&quot;: &quot;none&quot;},
    {&quot;phase&quot;: 5, &quot;owner&quot;: &quot;Agent&quot;, &quot;label&quot;: &quot;Formateo&quot;, &quot;io&quot;: &quot;none&quot;},
    {&quot;phase&quot;: 6, &quot;owner&quot;: &quot;Command&quot;, &quot;label&quot;: &quot;Entrega&quot;, &quot;io&quot;: &quot;external&quot;}
];

    function initPipeline() {
        const container = document.getElementById(containerId);
        if (!container) return;

        const canvas = container.querySelector(&#x27;.pipeline-canvas&#x27;);
        const ctx = canvas.getContext(&#x27;2d&#x27;);

        &#x2F;&#x2F; Responsive sizing
        function resize() {
            const rect = container.getBoundingClientRect();
            canvas.width = rect.width;
            canvas.height = 180;
        }
        resize();
        window.addEventListener(&#x27;resize&#x27;, resize);

        &#x2F;&#x2F; Colors
        const colors = {
            command: &#x27;#00d4ff&#x27;,
            agent: &#x27;#00ff88&#x27;,
            external: &#x27;#8b5cf6&#x27;,
            local: &#x27;#ff8800&#x27;,
            none: &#x27;#444466&#x27;,
            particle: &#x27;#00ff88&#x27;,
            bg: &#x27;rgba(10, 10, 15, 0.8)&#x27;
        };

        &#x2F;&#x2F; Animation state
        let particles = [];
        let time = 0;

        &#x2F;&#x2F; Get phase positions
        function getPhasePositions() {
            const phases = phasesData;
            const margin = 60;
            const spacing = (canvas.width - margin * 2) &#x2F; (phases.length - 1);
            return phases.map((p, i) =&gt; ({
                ...p,
                x: margin + i * spacing,
                y: canvas.height &#x2F; 2,
                radius: 24
            }));
        }

        &#x2F;&#x2F; Create particle
        function createParticle(positions) {
            return {
                phaseIndex: 0,
                progress: 0,
                speed: 0.01 + Math.random() * 0.01,
                x: positions[0].x,
                y: positions[0].y
            };
        }

        &#x2F;&#x2F; Draw
        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            const positions = getPhasePositions();

            &#x2F;&#x2F; Draw connections
            ctx.lineWidth = 2;
            ctx.strokeStyle = &#x27;rgba(0, 212, 255, 0.3)&#x27;;
            ctx.beginPath();
            positions.forEach((pos, i) =&gt; {
                if (i === 0) ctx.moveTo(pos.x, pos.y);
                else ctx.lineTo(pos.x, pos.y);
            });
            ctx.stroke();

            &#x2F;&#x2F; Draw arrows
            for (let i = 0; i &lt; positions.length - 1; i++) {
                const from = positions[i];
                const to = positions[i + 1];
                const midX = (from.x + to.x) &#x2F; 2;
                const midY = (from.y + to.y) &#x2F; 2;

                ctx.fillStyle = &#x27;rgba(0, 212, 255, 0.5)&#x27;;
                ctx.beginPath();
                ctx.moveTo(midX - 6, midY - 4);
                ctx.lineTo(midX + 6, midY);
                ctx.lineTo(midX - 6, midY + 4);
                ctx.closePath();
                ctx.fill();
            }

            &#x2F;&#x2F; Draw phase nodes
            positions.forEach((pos, i) =&gt; {
                const isCommand = pos.owner === &#x27;Command&#x27;;
                const color = isCommand ? colors.command : colors.agent;

                &#x2F;&#x2F; Glow
                const gradient = ctx.createRadialGradient(pos.x, pos.y, 0, pos.x, pos.y, pos.radius * 2);
                gradient.addColorStop(0, color.replace(&#x27;)&#x27;, &#x27;, 0.3)&#x27;).replace(&#x27;rgb&#x27;, &#x27;rgba&#x27;));
                gradient.addColorStop(1, &#x27;transparent&#x27;);
                ctx.fillStyle = gradient;
                ctx.beginPath();
                ctx.arc(pos.x, pos.y, pos.radius * 2, 0, Math.PI * 2);
                ctx.fill();

                &#x2F;&#x2F; Node
                ctx.fillStyle = color;
                ctx.beginPath();
                ctx.arc(pos.x, pos.y, pos.radius, 0, Math.PI * 2);
                ctx.fill();

                &#x2F;&#x2F; Phase number
                ctx.fillStyle = &#x27;#0a0a0f&#x27;;
                ctx.font = &#x27;bold 14px JetBrains Mono, monospace&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.textBaseline = &#x27;middle&#x27;;
                ctx.fillText(pos.phase, pos.x, pos.y);

                &#x2F;&#x2F; Label
                ctx.fillStyle = &#x27;#e0e0e4&#x27;;
                ctx.font = &#x27;11px JetBrains Mono, monospace&#x27;;
                ctx.fillText(pos.label, pos.x, pos.y + pos.radius + 16);

                &#x2F;&#x2F; I&#x2F;O indicator
                if (pos.io !== &#x27;none&#x27;) {
                    ctx.fillStyle = pos.io === &#x27;external&#x27; ? colors.external : colors.local;
                    ctx.font = &#x27;9px JetBrains Mono, monospace&#x27;;
                    ctx.fillText(pos.io.toUpperCase(), pos.x, pos.y - pos.radius - 10);
                }
            });

            &#x2F;&#x2F; Update and draw particles
            particles.forEach(p =&gt; {
                if (p.phaseIndex &gt;= positions.length - 1) {
                    p.phaseIndex = 0;
                    p.progress = 0;
                }

                const from = positions[p.phaseIndex];
                const to = positions[p.phaseIndex + 1];

                p.progress += p.speed;
                if (p.progress &gt;= 1) {
                    p.phaseIndex++;
                    p.progress = 0;
                }

                if (to) {
                    p.x = from.x + (to.x - from.x) * p.progress;
                    p.y = from.y + (to.y - from.y) * p.progress;
                }

                &#x2F;&#x2F; Draw particle
                ctx.fillStyle = colors.particle;
                ctx.beginPath();
                ctx.arc(p.x, p.y, 4, 0, Math.PI * 2);
                ctx.fill();

                &#x2F;&#x2F; Particle glow
                const pGrad = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, 12);
                pGrad.addColorStop(0, &#x27;rgba(0, 255, 136, 0.4)&#x27;);
                pGrad.addColorStop(1, &#x27;transparent&#x27;);
                ctx.fillStyle = pGrad;
                ctx.beginPath();
                ctx.arc(p.x, p.y, 12, 0, Math.PI * 2);
                ctx.fill();
            });

            time++;
            requestAnimationFrame(draw);
        }

        &#x2F;&#x2F; Initialize particles
        const positions = getPhasePositions();
        for (let i = 0; i &lt; 3; i++) {
            const p = createParticle(positions);
            p.phaseIndex = i * 2;
            particles.push(p);
        }

        &#x2F;&#x2F; Respect reduced motion
        if (!window.matchMedia(&#x27;(prefers-reduced-motion: reduce)&#x27;).matches) {
            draw();
        } else {
            &#x2F;&#x2F; Static version
            const positions = getPhasePositions();
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            ctx.lineWidth = 2;
            ctx.strokeStyle = &#x27;rgba(0, 212, 255, 0.5)&#x27;;
            ctx.beginPath();
            positions.forEach((pos, i) =&gt; {
                if (i === 0) ctx.moveTo(pos.x, pos.y);
                else ctx.lineTo(pos.x, pos.y);
            });
            ctx.stroke();

            positions.forEach((pos) =&gt; {
                const color = pos.owner === &#x27;Command&#x27; ? colors.command : colors.agent;
                ctx.fillStyle = color;
                ctx.beginPath();
                ctx.arc(pos.x, pos.y, pos.radius, 0, Math.PI * 2);
                ctx.fill();

                ctx.fillStyle = &#x27;#0a0a0f&#x27;;
                ctx.font = &#x27;bold 14px JetBrains Mono, monospace&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.textBaseline = &#x27;middle&#x27;;
                ctx.fillText(pos.phase, pos.x, pos.y);

                ctx.fillStyle = &#x27;#e0e0e4&#x27;;
                ctx.font = &#x27;11px JetBrains Mono, monospace&#x27;;
                ctx.fillText(pos.label, pos.x, pos.y + pos.radius + 16);
            });
        }
    }

    if (document.readyState === &#x27;loading&#x27;) {
        document.addEventListener(&#x27;DOMContentLoaded&#x27;, initPipeline);
    } else {
        initPipeline();
    }
})();
&lt;&#x2F;script&gt;

&lt;style&gt;
.pipeline-container {
    background: var(--bg-0);
    border: 1px solid var(--divider-color);
    border-radius: 12px;
    padding: 1.5rem 1rem 1rem;
    margin: 1.5rem 0;
    position: relative;
}

.pipeline-canvas {
    width: 100%;
    height: 180px;
    display: block;
}

.pipeline-legend {
    display: flex;
    justify-content: center;
    gap: 2rem;
    margin-top: 0.5rem;
    font-family: &#x27;JetBrains Mono&#x27;, monospace;
    font-size: 0.8rem;
    color: var(--meta-color);
}

.legend-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.legend-dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
}

.legend-dot.command {
    background: #00d4ff;
}

.legend-dot.agent {
    background: #00ff88;
}

@media (max-width: 768px) {
    .pipeline-container {
        overflow-x: auto;
    }

    .pipeline-canvas {
        min-width: 600px;
    }
}
&lt;&#x2F;style&gt;
&lt;p&gt;&lt;strong&gt;Generalizabilidad&lt;&#x2F;strong&gt;: Esta separación aplica a cualquier framework donde existan restricciones de acceso a herramientas. La capa de inteligencia se vuelve portable y testeable en aislamiento. La capa de I&#x2F;O se convierte en el adaptador específico de plataforma.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4-2-validacion-basada-en-fases&quot;&gt;4.2 Validación Basada en Fases&lt;&#x2F;h3&gt;
&lt;p&gt;Cada transición de fase representa un checkpoint de validación:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Checkpoint&lt;&#x2F;th&gt;&lt;th&gt;Validación&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Pre-fase&lt;&#x2F;td&gt;&lt;td&gt;Verificación de contrato de entrada&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Mid-fase&lt;&#x2F;td&gt;&lt;td&gt;Checkpoint de progreso&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Post-fase&lt;&#x2F;td&gt;&lt;td&gt;Cumplimiento de contrato de salida&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Inter-fase&lt;&#x2F;td&gt;&lt;td&gt;Validación de transformación de datos&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;Estrategias de Recuperación de Errores&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Rollback al último estado válido&lt;&#x2F;li&gt;
&lt;li&gt;Reintentar con parámetros modificados&lt;&#x2F;li&gt;
&lt;li&gt;Escalar a modo fallback&lt;&#x2F;li&gt;
&lt;li&gt;Preservar resultados parciales&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;4-3-degradacion-graciosa&quot;&gt;4.3 Degradación Graciosa&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Patrón FALLBACK_MODE&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;Cuando los servicios externos se vuelven no disponibles, el sistema degrada graciosamente:&lt;&#x2F;p&gt;









&lt;div class=&quot;comparison-container&quot; id=&quot;comparis&quot;&gt;
    &lt;canvas class=&quot;comparison-canvas&quot; aria-label=&quot;Mode comparison visualization&quot;&gt;&lt;&#x2F;canvas&gt;
&lt;&#x2F;div&gt;

&lt;script&gt;
(function() {
    const containerId = &#x27;comparis&#x27;;
    const mode1Title = &#x27;Modo Normal&#x27;;
    const mode1Steps = [&#x27;Fase 1: Resolver MCP&#x27;, &#x27;Fase 3: Verificar Dups&#x27;, &#x27;Fase 6: Crear Issue&#x27;];
    const mode2Title = &#x27;Modo Fallback&#x27;;
    const mode2Steps = [&#x27;Fase 1: Saltar&#x27;, &#x27;Fase 3: Saltar&#x27;, &#x27;Fase 6: Archivo Local&#x27;];
    const sharedTitle = &#x27;Capa de Inteligencia (Siempre Activa)&#x27;;
    const sharedSteps = [&#x27;Fase 4: Razonamiento&#x27;, &#x27;Fase 5: Formateo&#x27;];

    function initComparison() {
        const container = document.getElementById(containerId);
        if (!container) return;

        const canvas = container.querySelector(&#x27;.comparison-canvas&#x27;);
        const ctx = canvas.getContext(&#x27;2d&#x27;);

        let particles = [];
        let time = 0;

        const colors = {
            mode1: &#x27;#00d4ff&#x27;,
            mode2: &#x27;#ff8800&#x27;,
            shared: &#x27;#00ff88&#x27;,
            skip: &#x27;#444466&#x27;,
            particle: &#x27;#00ff88&#x27;,
            connection: &#x27;rgba(255, 255, 255, 0.2)&#x27;,
            text: &#x27;#e0e0e4&#x27;,
            subtext: &#x27;#8888a0&#x27;
        };

        function resize() {
            const rect = container.getBoundingClientRect();
            canvas.width = rect.width;
            canvas.height = 320;
        }
        resize();
        window.addEventListener(&#x27;resize&#x27;, resize);

        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            const leftX = canvas.width * 0.25;
            const rightX = canvas.width * 0.75;
            const centerX = canvas.width &#x2F; 2;

            const headerY = 35;
            const stepsStartY = 80;
            const stepSpacing = 45;
            const sharedY = 240;

            &#x2F;&#x2F; Draw mode headers
            function drawHeader(x, title, color) {
                ctx.fillStyle = color;
                ctx.font = &#x27;bold 14px JetBrains Mono&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.shadowColor = color;
                ctx.shadowBlur = 10;
                ctx.fillText(title, x, headerY);
                ctx.shadowBlur = 0;

                &#x2F;&#x2F; Underline
                ctx.strokeStyle = color;
                ctx.lineWidth = 2;
                ctx.beginPath();
                ctx.moveTo(x - 60, headerY + 8);
                ctx.lineTo(x + 60, headerY + 8);
                ctx.stroke();
            }

            drawHeader(leftX, mode1Title, colors.mode1);
            drawHeader(rightX, mode2Title, colors.mode2);

            &#x2F;&#x2F; Draw steps for each mode
            function drawStep(x, y, text, color, isSkip) {
                const width = 130;
                const height = 32;

                ctx.shadowColor = color;
                ctx.shadowBlur = isSkip ? 0 : 12;

                ctx.fillStyle = isSkip ? colors.skip : color;
                ctx.beginPath();
                ctx.roundRect(x - width&#x2F;2, y - height&#x2F;2, width, height, 6);
                ctx.fill();

                ctx.shadowBlur = 0;

                if (!isSkip) {
                    ctx.strokeStyle = &#x27;#00ff88&#x27;;
                    ctx.lineWidth = 1;
                    ctx.stroke();
                } else {
                    ctx.setLineDash([4, 4]);
                    ctx.strokeStyle = &#x27;#666&#x27;;
                    ctx.lineWidth = 1;
                    ctx.stroke();
                    ctx.setLineDash([]);
                }

                ctx.fillStyle = isSkip ? &#x27;#666&#x27; : &#x27;#0a0a0f&#x27;;
                ctx.font = isSkip ? &#x27;10px JetBrains Mono&#x27; : &#x27;bold 10px JetBrains Mono&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.textBaseline = &#x27;middle&#x27;;
                ctx.fillText(text, x, y);

                return { x, y, width, height };
            }

            &#x2F;&#x2F; Mode 1 steps
            const mode1Nodes = [];
            mode1Steps.forEach((step, i) =&gt; {
                const y = stepsStartY + i * stepSpacing;
                mode1Nodes.push(drawStep(leftX, y, step, colors.mode1, false));
            });

            &#x2F;&#x2F; Mode 2 steps
            const mode2Nodes = [];
            mode2Steps.forEach((step, i) =&gt; {
                const y = stepsStartY + i * stepSpacing;
                const isSkip = step.toLowerCase().includes(&#x27;skip&#x27;);
                mode2Nodes.push(drawStep(rightX, y, step, colors.mode2, isSkip));
            });

            &#x2F;&#x2F; Connections between steps
            ctx.strokeStyle = colors.connection;
            ctx.lineWidth = 1;

            for (let i = 0; i &lt; mode1Nodes.length - 1; i++) {
                const from = mode1Nodes[i];
                const to = mode1Nodes[i + 1];
                ctx.beginPath();
                ctx.moveTo(from.x, from.y + from.height&#x2F;2);
                ctx.lineTo(to.x, to.y - to.height&#x2F;2);
                ctx.stroke();
            }

            for (let i = 0; i &lt; mode2Nodes.length - 1; i++) {
                const from = mode2Nodes[i];
                const to = mode2Nodes[i + 1];
                ctx.beginPath();
                ctx.moveTo(from.x, from.y + from.height&#x2F;2);
                ctx.lineTo(to.x, to.y - to.height&#x2F;2);
                ctx.stroke();
            }

            &#x2F;&#x2F; Shared section
            ctx.fillStyle = colors.shared;
            ctx.font = &#x27;bold 13px JetBrains Mono&#x27;;
            ctx.textAlign = &#x27;center&#x27;;
            ctx.shadowColor = colors.shared;
            ctx.shadowBlur = 10;
            ctx.fillText(sharedTitle, centerX, sharedY - 25);
            ctx.shadowBlur = 0;

            &#x2F;&#x2F; Shared steps box
            const sharedWidth = 200;
            const sharedHeight = 50;
            ctx.fillStyle = &#x27;rgba(0, 255, 136, 0.15)&#x27;;
            ctx.strokeStyle = colors.shared;
            ctx.lineWidth = 2;
            ctx.beginPath();
            ctx.roundRect(centerX - sharedWidth&#x2F;2, sharedY - 10, sharedWidth, sharedHeight, 8);
            ctx.fill();
            ctx.stroke();

            &#x2F;&#x2F; Shared step text
            ctx.fillStyle = colors.text;
            ctx.font = &#x27;11px JetBrains Mono&#x27;;
            sharedSteps.forEach((step, i) =&gt; {
                ctx.fillText(step, centerX, sharedY + 8 + i * 16);
            });

            &#x2F;&#x2F; Arrows from both modes to shared
            ctx.strokeStyle = colors.connection;
            ctx.lineWidth = 2;

            &#x2F;&#x2F; Left arrow
            const lastMode1 = mode1Nodes[mode1Nodes.length - 1];
            ctx.beginPath();
            ctx.moveTo(lastMode1.x, lastMode1.y + lastMode1.height&#x2F;2);
            ctx.quadraticCurveTo(lastMode1.x, sharedY - 30, centerX - sharedWidth&#x2F;2, sharedY + 15);
            ctx.stroke();

            &#x2F;&#x2F; Right arrow
            const lastMode2 = mode2Nodes[mode2Nodes.length - 1];
            ctx.beginPath();
            ctx.moveTo(lastMode2.x, lastMode2.y + lastMode2.height&#x2F;2);
            ctx.quadraticCurveTo(lastMode2.x, sharedY - 30, centerX + sharedWidth&#x2F;2, sharedY + 15);
            ctx.stroke();

            &#x2F;&#x2F; &quot;Always Active&quot; badge
            ctx.fillStyle = colors.shared;
            ctx.font = &#x27;bold 9px JetBrains Mono&#x27;;
            ctx.fillText(&#x27;✓ ALWAYS ACTIVE&#x27;, centerX, sharedY + sharedHeight + 8);

            &#x2F;&#x2F; Animate particles
            particles.forEach(p =&gt; {
                p.progress += p.speed;
                if (p.progress &gt;= 1) {
                    p.progress = 0;
                    p.side = p.side === &#x27;left&#x27; ? &#x27;right&#x27; : &#x27;left&#x27;;
                }

                const nodes = p.side === &#x27;left&#x27; ? mode1Nodes : mode2Nodes;
                const segmentIndex = Math.floor(p.progress * nodes.length);
                const segmentProgress = (p.progress * nodes.length) % 1;

                if (segmentIndex &lt; nodes.length - 1) {
                    const from = nodes[segmentIndex];
                    const to = nodes[segmentIndex + 1];
                    const x = from.x + (to.x - from.x) * segmentProgress;
                    const y = from.y + (to.y - from.y) * segmentProgress;

                    ctx.fillStyle = colors.particle;
                    ctx.shadowColor = colors.particle;
                    ctx.shadowBlur = 10;
                    ctx.beginPath();
                    ctx.arc(x, y, 4, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.shadowBlur = 0;
                }
            });

            time++;
            requestAnimationFrame(draw);
        }

        &#x2F;&#x2F; Initialize particles
        particles.push({ side: &#x27;left&#x27;, progress: 0, speed: 0.008 });
        particles.push({ side: &#x27;right&#x27;, progress: 0.5, speed: 0.008 });

        if (!window.matchMedia(&#x27;(prefers-reduced-motion: reduce)&#x27;).matches) {
            draw();
        } else {
            draw();
            &#x2F;&#x2F; Just draw once for static
        }
    }

    if (document.readyState === &#x27;loading&#x27;) {
        document.addEventListener(&#x27;DOMContentLoaded&#x27;, initComparison);
    } else {
        initComparison();
    }
})();
&lt;&#x2F;script&gt;

&lt;style&gt;
.comparison-container {
    background: var(--bg-0);
    border: 1px solid var(--divider-color);
    border-radius: 12px;
    padding: 1rem;
    margin: 1.5rem 0;
    position: relative;
}

.comparison-canvas {
    width: 100%;
    height: 320px;
    display: block;
}

@media (max-width: 768px) {
    .comparison-container {
        overflow-x: auto;
    }

    .comparison-canvas {
        min-width: 500px;
    }
}
&lt;&#x2F;style&gt;
&lt;p&gt;Las capas de inteligencia (Fases 4-5) funcionan idénticamente en ambos modos. El razonamiento core se preserva incluso cuando las capacidades de I&#x2F;O están reducidas.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;5-implicaciones-para-diseno-de-frameworks&quot;&gt;5. Implicaciones para Diseño de Frameworks&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;5-1-filosofia-de-acceso-a-herramientas&quot;&gt;5.1 Filosofía de Acceso a Herramientas&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Recomendación&lt;&#x2F;strong&gt;: Preferir declaraciones explícitas de herramientas sobre herencia implícita.&lt;&#x2F;p&gt;
&lt;p&gt;La paradoja de la herencia demuestra que los modelos implícitos crean límites de scope inesperados. Las declaraciones explícitas, aunque verbose, producen comportamiento predecible:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Explícito (recomendado)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;tools&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Read&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Write&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Grep&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Implícito (problemático)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;tools&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;inherit&lt;&#x2F;span&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Comportamiento varía por contexto
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;5-2-fidelidad-de-documentacion&quot;&gt;5.2 Fidelidad de Documentación&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Requisito&lt;&#x2F;strong&gt;: La implementación debe coincidir con la documentación.&lt;&#x2F;p&gt;
&lt;p&gt;La brecha entre comportamiento documentado y real de MCP consumió esfuerzo significativo de debugging. Pruebas automatizadas de comportamientos documentados captarían tales discrepancias antes de que lleguen a usuarios.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;5-3-testing-en-contextos-reales&quot;&gt;5.3 Testing en Contextos Reales&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Requisito&lt;&#x2F;strong&gt;: Probar con restricciones reales de plataforma.&lt;&#x2F;p&gt;
&lt;p&gt;El acceso MCP funciona en testing aislado pero falla en contextos de plugin. Los tests de integración deben ejecutarse en ambientes similares a producción con límites de scope reales.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;5-4-consideraciones-de-experiencia-de-desarrollador&quot;&gt;5.4 Consideraciones de Experiencia de Desarrollador&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Observación&lt;&#x2F;strong&gt;: Los requisitos complejos de deployment desalientan la experimentación.&lt;&#x2F;p&gt;
&lt;p&gt;El requisito de sincronización en tres ubicaciones, falta de hot reload, y validación estricta de schema añaden fricción al ciclo de desarrollo. Cada restricción añade aproximadamente 2-5 minutos por ciclo de cambio versus segundos para sistemas con hot-reload.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Análisis de Trade-off&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Restricción&lt;&#x2F;th&gt;&lt;th&gt;Beneficio&lt;&#x2F;th&gt;&lt;th&gt;Costo&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Sync en tres ubicaciones&lt;&#x2F;td&gt;&lt;td&gt;Consistencia de versión&lt;&#x2F;td&gt;&lt;td&gt;Overhead de sync manual&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Sin hot reload&lt;&#x2F;td&gt;&lt;td&gt;Predictabilidad de estado&lt;&#x2F;td&gt;&lt;td&gt;Delay de reinicio&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Schema estricto&lt;&#x2F;td&gt;&lt;td&gt;Detección temprana de errores&lt;&#x2F;td&gt;&lt;td&gt;Dificultad de debugging&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;6-conclusion&quot;&gt;6. Conclusión&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;resumen-de-contribuciones&quot;&gt;Resumen de Contribuciones&lt;&#x2F;h3&gt;
&lt;p&gt;Este estudio empírico del desarrollo de plugins de Claude Code revela patrones aplicables al diseño de sistemas IA multi-agente:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;La Paradoja de la Herencia&lt;&#x2F;strong&gt;: Los modelos de herencia de acceso a herramientas documentados en especificaciones pueden no funcionar a través de todos los límites de scope. Los contratos explícitos previenen comportamiento inesperado.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Arquitectura Impulsada por Topología&lt;&#x2F;strong&gt;: Las restricciones impuestas por plataforma (como anidamiento de un solo nivel) impulsan la emergencia de patrones específicos (hub-and-spoke) que pueden ser superiores a diseños sin restricciones.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Naming como Comportamiento&lt;&#x2F;strong&gt;: En sistemas de agentes IA, las convenciones de nombres llevan implicaciones funcionales más allá del etiquetado.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Separación I&#x2F;O&lt;&#x2F;strong&gt;: Separar I&#x2F;O de inteligencia crea sistemas portables, testeables, con degradación graciosa.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;limitaciones&quot;&gt;Limitaciones&lt;&#x2F;h3&gt;
&lt;p&gt;Este estudio está basado en observaciones de una sola plataforma (Claude Code) durante un período específico de desarrollo. Los hallazgos pueden no generalizarse a todos los frameworks de agentes. Adicionalmente, el comportamiento de la plataforma puede cambiar a medida que se resuelven bugs.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;direcciones-futuras-de-investigacion&quot;&gt;Direcciones Futuras de Investigación&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;Análisis comparativo de modelos de herencia de herramientas a través de plataformas de agentes&lt;&#x2F;li&gt;
&lt;li&gt;Especificación formal de contratos de scope para sistemas multi-agente&lt;&#x2F;li&gt;
&lt;li&gt;Estudios empíricos de acoplamiento naming-comportamiento en otros sistemas IA&lt;&#x2F;li&gt;
&lt;li&gt;Patrones de diseño de frameworks que explícitamente aprovechan restricciones de topología&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;apendice-resumen-de-evidencia&quot;&gt;Apéndice: Resumen de Evidencia&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;issues-de-github-referenciados&quot;&gt;Issues de GitHub Referenciados&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Issue&lt;&#x2F;th&gt;&lt;th&gt;Descripción&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;#13605&lt;&#x2F;td&gt;&lt;td&gt;Agentes de plugin personalizados no pueden acceder a MCP&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;#15810&lt;&#x2F;td&gt;&lt;td&gt;Subagentes no heredan MCP de agentes definidos en plugins&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;#14496&lt;&#x2F;td&gt;&lt;td&gt;Acceso inconsistente a MCP con prompts complejos&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;#7296&lt;&#x2F;td&gt;&lt;td&gt;Fallo de herencia de scope para agentes lanzados con Task&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;metricas-de-investigacion&quot;&gt;Métricas de Investigación&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Período de Observación&lt;&#x2F;strong&gt;: Enero 3-4, 2026&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Inversión de Tokens&lt;&#x2F;strong&gt;: ~265,000 tokens a través de sesiones&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Observaciones Distintas&lt;&#x2F;strong&gt;: 13 hallazgos documentados&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Tipos de Hallazgo&lt;&#x2F;strong&gt;: 4 Decisiones, 8 Descubrimientos, 1 Cambio&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;metodologia&quot;&gt;Metodología&lt;&#x2F;h3&gt;
&lt;p&gt;Las observaciones fueron recolectadas a través de sesiones de desarrollo usando el sistema de memoria persistente claude-mem. Cada hallazgo fue cruzado contra documentación y, donde aplicable, reportes de issues de GitHub. Los workarounds fueron desarrollados a través de experimentación iterativa.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;obten-el-plugin&quot;&gt;Obtén el Plugin&lt;&#x2F;h2&gt;
&lt;p&gt;El plugin discutido en esta investigación es open source: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Cpicon&#x2F;claude-code-plugins&quot;&gt;Cpicon&#x2F;claude-code-plugins&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Usa la pestaña &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Cpicon&#x2F;claude-code-plugins&#x2F;issues&quot;&gt;GitHub Issues&lt;&#x2F;a&gt; para solicitar features, reportar bugs, o discutir mejoras.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Navegación de la Serie:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Parte 0&lt;&#x2F;strong&gt;: &lt;a href=&quot;&#x2F;posts&#x2F;claude-code-plugin-journey-part0&#x2F;&quot;&gt;Agent Team Creator&lt;&#x2F;a&gt; — Qué hace el plugin y cómo usarlo&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Parte 1&lt;&#x2F;strong&gt;: &lt;a href=&quot;&#x2F;posts&#x2F;claude-code-plugin-journey-part1&#x2F;&quot;&gt;El Patrón de Arquitectura Híbrida&lt;&#x2F;a&gt; — Construyendo el plugin, lecciones aprendidas&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Parte 2&lt;&#x2F;strong&gt; (Estás aquí): Insights de investigación, patrones&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Este artículo está basado en observaciones empíricas del desarrollo del plugin agent-team-creator de Claude Code. Para guía práctica de implementación, ve Parte 1.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        <summary type="html">La Paradoja de la Herencia: Scoping de Herramientas en Sistemas Multi-Agente

Esta es la Parte 2 de una serie de tres partes. Ve Parte 0 para la visión general del plugin e instalación, o Parte 1 para el viaje de desarrollo.

Resumen: Este artículo presenta observaciones empíricas del desarrollo de un plugin de Claude Code, revelando patrones fundamentales en el diseño de sistemas IA multi-agente. A través de sesiones de desarrollo documentadas, identificamos tres hallazgos clave: (1) los modelos de herencia implícita de herramientas fallan consistentemente en la práctica, requiriendo contratos de scope explícitos; (2) las restricciones de topología impuestas por la plataforma impulsan la emergencia de patrones arquitectónicos específicos; y (3) las convenciones de nombres se convierten en requisitos funcionales en sistemas IA. Estos hallazgos tienen implicaciones para el diseño de frameworks de agentes más allá de la plataforma específica estudiada.
…</summary>
        </entry><entry xml:lang="es">
        <title>El Patrón de Arquitectura Híbrida: Lecciones de agent-team-creator</title>
        <published>2026-01-06T11:00:00+00:00</published>
        <updated>2026-01-06T11:00:00+00:00</updated>
        <author>
            <name>Christian Picon Calderon</name>
        </author>
        <link rel="alternate" href="https://futurewithml.netlify.app/es/posts/claude-code-plugin-journey-part1/" type="text/html"/>
        <id>https://futurewithml.netlify.app/es/posts/claude-code-plugin-journey-part1/</id>
        
            <content type="html">&lt;h1 id=&quot;el-patron-de-arquitectura-hibrida-lecciones-de-agent-team-creator&quot;&gt;El Patrón de Arquitectura Híbrida: Lecciones de agent-team-creator&lt;&#x2F;h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Esta es la Parte 1 de una serie de tres partes. Comienza con &lt;a href=&quot;&#x2F;posts&#x2F;claude-code-plugin-journey-part0&#x2F;&quot;&gt;Parte 0: Agent Team Creator&lt;&#x2F;a&gt; para ver qué hace el plugin, o continúa aquí para el viaje de desarrollo.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Pensé que construir un plugin de Claude Code tomaría un fin de semana. Tres días después de luchar con bugs de acceso a herramientas MCP, sincronización de archivos en tres ubicaciones, y documentación que prometía features que no funcionaban, me di cuenta de que estaba construyendo algo más valioso que un plugin—estaba mapeando territorio inexplorado.&lt;&#x2F;p&gt;
&lt;p&gt;Esta es la historia de construir &lt;strong&gt;agent-team-creator&lt;&#x2F;strong&gt;, un plugin de Claude Code que analiza códigos base y genera agentes IA específicos del proyecto. En el camino, descubrí un patrón que convirtió las limitaciones de la plataforma en claridad arquitectónica: el &lt;strong&gt;Patrón de Arquitectura Híbrida&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;acto-i-la-configuracion&quot;&gt;Acto I: La Configuración&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;la-vision&quot;&gt;La Visión&lt;&#x2F;h3&gt;
&lt;p&gt;La idea era simple: analizar cualquier código base y generar automáticamente un equipo de agentes Claude Code especializados adaptados a ese proyecto. ¿Un frontend React? Genera un agente diseñador de componentes. ¿Un pipeline ML de Python? Spawn un agente entrenador de modelos. El plugin entendería tu código y crearía colaboradores IA que hablan el lenguaje de tu proyecto.&lt;&#x2F;p&gt;
&lt;p&gt;Había leído la documentación. Los plugins de Claude Code soportan cinco tipos de componentes—commands, agents, skills, hooks, e integraciones MCP. Los agentes pueden spawnear subagentes usando la herramienta Task. Los servidores MCP proveen acceso a servicios externos. Parecía directo.&lt;&#x2F;p&gt;
&lt;p&gt;Esto es lo que esperaba versus lo que encontré:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Expectativa&lt;&#x2F;th&gt;&lt;th&gt;Realidad&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Los agentes de plugin pueden acceder a herramientas MCP&lt;&#x2F;td&gt;&lt;td&gt;Los agentes de plugin &lt;strong&gt;no pueden&lt;&#x2F;strong&gt; acceder a MCP (bug documentado)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Los agentes pueden spawnear subagentes anidados&lt;&#x2F;td&gt;&lt;td&gt;Solo un nivel de anidamiento&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;La documentación describe el comportamiento real&lt;&#x2F;td&gt;&lt;td&gt;Los docs dicen que MCP funciona, pero no lo hace&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Los cambios se propagan automáticamente&lt;&#x2F;td&gt;&lt;td&gt;Se requiere sincronización manual en 3 ubicaciones&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;La herencia de modelo funciona&lt;&#x2F;td&gt;&lt;td&gt;Por defecto usa Sonnet 4 sin importar la configuración&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;La brecha entre expectativa y realidad se convertiría en mi currículo.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;entendiendo-el-terreno&quot;&gt;Entendiendo el Terreno&lt;&#x2F;h3&gt;
&lt;p&gt;Antes de profundizar en los puntos de dolor, déjame compartir el panorama. Los plugins de Claude Code tienen cinco tipos de componentes, cada uno con mecanismos de activación distintos:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Componente&lt;&#x2F;th&gt;&lt;th&gt;Activador&lt;&#x2F;th&gt;&lt;th&gt;Propósito&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Skills&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Auto-invocados&lt;&#x2F;td&gt;&lt;td&gt;Proveedores de contexto basados en matching de descripción&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Commands&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Iniciado por usuario (&lt;code&gt;&#x2F;command&lt;&#x2F;code&gt;)&lt;&#x2F;td&gt;&lt;td&gt;Atajos de comandos slash&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Agents&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Spawneados via herramienta Task&lt;&#x2F;td&gt;&lt;td&gt;Instancias separadas de Claude para trabajo especializado&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Hooks&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Basados en eventos&lt;&#x2F;td&gt;&lt;td&gt;Handlers de automatización (PreToolUse, PostToolUse, etc.)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;MCPs&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Llamadas a herramientas&lt;&#x2F;td&gt;&lt;td&gt;Integraciones de servicios externos&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;La estructura de directorios sigue un patrón predecible:&lt;&#x2F;p&gt;





&lt;div class=&quot;tree-container&quot; id=&quot;tree-202&quot;&gt;
    &lt;canvas class=&quot;tree-canvas&quot; aria-label=&quot;Directory structure visualization&quot;&gt;&lt;&#x2F;canvas&gt;
&lt;&#x2F;div&gt;

&lt;script&gt;
(function() {
    const containerId = &#x27;tree-202&#x27;;

    &#x2F;&#x2F; Decode HTML entities (Tera encodes &#x2F; as &amp;#x2F;)
    function decodeHTML(str) {
        const textarea = document.createElement(&#x27;textarea&#x27;);
        textarea.innerHTML = str;
        return textarea.value;
    }

    const rootName = decodeHTML(&#x27;plugin-root&#x27;);
    const nodeData = decodeHTML(&#x27;.claude-plugin&amp;#x2F;:marketplace.json;plugin.json,commands&amp;#x2F;:*.md,agents&amp;#x2F;:*.md,skills&amp;#x2F;:SKILL.md,hooks&amp;#x2F;:*.md,.mcp.json:config&#x27;);

    function parseNodes(data) {
        const folders = [];
        data.split(&#x27;,&#x27;).forEach(folder =&gt; {
            const [name, childrenStr] = folder.split(&#x27;:&#x27;);
            const children = childrenStr ? childrenStr.split(&#x27;;&#x27;).map(c =&gt; c.trim()) : [];
            folders.push({ name: name.trim(), children, type: &#x27;folder&#x27; });
        });
        return folders;
    }

    function initTree() {
        const container = document.getElementById(containerId);
        if (!container) return;

        const canvas = container.querySelector(&#x27;.tree-canvas&#x27;);
        const ctx = canvas.getContext(&#x27;2d&#x27;);

        let particles = [];
        let time = 0;

        const colors = {
            root: &#x27;#ff0080&#x27;,
            folder: &#x27;#00d4ff&#x27;,
            file: &#x27;#8b5cf6&#x27;,
            config: &#x27;#ff8800&#x27;,
            accent: &#x27;#00ff88&#x27;,
            connection: &#x27;rgba(0, 212, 255, 0.3)&#x27;,
            text: &#x27;#e0e0e4&#x27;
        };

        const folders = parseNodes(nodeData);

        function resize() {
            const rect = container.getBoundingClientRect();
            canvas.width = rect.width;
            canvas.height = 320;
        }
        resize();
        window.addEventListener(&#x27;resize&#x27;, resize);

        function getNodePositions() {
            const nodes = [];
            const centerX = canvas.width &#x2F; 2;
            const rootY = 50;
            const folderY = 140;
            const fileY = 230;

            &#x2F;&#x2F; Root node
            nodes.push({
                type: &#x27;root&#x27;,
                label: rootName,
                x: centerX,
                y: rootY,
                radius: 28,
                color: colors.root
            });

            &#x2F;&#x2F; Folder nodes
            const folderSpacing = Math.min(120, (canvas.width - 100) &#x2F; folders.length);
            const startX = centerX - ((folders.length - 1) * folderSpacing) &#x2F; 2;

            folders.forEach((folder, i) =&gt; {
                const x = startX + i * folderSpacing;
                const isConfig = folder.name.includes(&#x27;.&#x27;) || folder.name.includes(&#x27;json&#x27;);

                nodes.push({
                    type: &#x27;folder&#x27;,
                    label: folder.name,
                    x: x,
                    y: folderY,
                    radius: 22,
                    color: isConfig ? colors.config : colors.folder,
                    parentIndex: 0,
                    children: folder.children
                });
            });

            &#x2F;&#x2F; File nodes (spread under their parent folders)
            let fileIndex = 0;
            folders.forEach((folder, folderIdx) =&gt; {
                const parentNode = nodes[folderIdx + 1];
                const childCount = folder.children.length;

                folder.children.forEach((child, childIdx) =&gt; {
                    const offset = (childIdx - (childCount - 1) &#x2F; 2) * 50;
                    nodes.push({
                        type: &#x27;file&#x27;,
                        label: child,
                        x: parentNode.x + offset,
                        y: fileY + (childIdx % 2) * 35,
                        radius: 18,
                        color: colors.file,
                        parentIndex: folderIdx + 1
                    });
                    fileIndex++;
                });
            });

            return nodes;
        }

        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            const nodes = getNodePositions();

            &#x2F;&#x2F; Draw connections
            ctx.strokeStyle = colors.connection;
            ctx.lineWidth = 2;

            nodes.forEach((node, i) =&gt; {
                if (node.parentIndex !== undefined) {
                    const parent = nodes[node.parentIndex];
                    ctx.beginPath();
                    ctx.moveTo(parent.x, parent.y + parent.radius);
                    ctx.lineTo(node.x, node.y - node.radius);
                    ctx.stroke();
                }
            });

            &#x2F;&#x2F; Draw nodes
            nodes.forEach((node, i) =&gt; {
                &#x2F;&#x2F; Glow effect
                ctx.shadowColor = node.color;
                ctx.shadowBlur = 15;

                &#x2F;&#x2F; Node circle
                ctx.fillStyle = node.color;
                ctx.beginPath();
                ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
                ctx.fill();

                ctx.shadowBlur = 0;

                &#x2F;&#x2F; Border
                ctx.strokeStyle = colors.accent;
                ctx.lineWidth = 2;
                ctx.stroke();

                &#x2F;&#x2F; Icon based on type
                ctx.fillStyle = &#x27;#0a0a0f&#x27;;
                ctx.font = node.type === &#x27;root&#x27; ? &#x27;16px sans-serif&#x27; : &#x27;12px sans-serif&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.textBaseline = &#x27;middle&#x27;;

                if (node.type === &#x27;root&#x27;) {
                    ctx.fillText(&#x27;📁&#x27;, node.x, node.y);
                } else if (node.type === &#x27;folder&#x27;) {
                    ctx.fillText(&#x27;📂&#x27;, node.x, node.y);
                } else {
                    ctx.fillText(&#x27;📄&#x27;, node.x, node.y);
                }

                &#x2F;&#x2F; Label
                ctx.fillStyle = colors.text;
                ctx.font = node.type === &#x27;root&#x27; ? &#x27;bold 12px JetBrains Mono&#x27; : &#x27;10px JetBrains Mono&#x27;;
                ctx.fillText(node.label, node.x, node.y + node.radius + 14);
            });

            &#x2F;&#x2F; Animated particles
            if (time % 60 === 0 &amp;&amp; particles.length &lt; 8) {
                const randomFolder = Math.floor(Math.random() * folders.length) + 1;
                const parentNode = nodes[randomFolder];
                if (parentNode) {
                    particles.push({
                        x: nodes[0].x,
                        y: nodes[0].y,
                        targetX: parentNode.x,
                        targetY: parentNode.y,
                        progress: 0,
                        speed: 0.02
                    });
                }
            }

            particles = particles.filter(p =&gt; p.progress &lt; 1);
            particles.forEach(p =&gt; {
                p.progress += p.speed;
                const ease = p.progress * p.progress * (3 - 2 * p.progress);
                const x = p.x + (p.targetX - p.x) * ease;
                const y = p.y + (p.targetY - p.y) * ease;

                ctx.fillStyle = colors.accent;
                ctx.shadowColor = colors.accent;
                ctx.shadowBlur = 10;
                ctx.beginPath();
                ctx.arc(x, y, 4, 0, Math.PI * 2);
                ctx.fill();
                ctx.shadowBlur = 0;
            });

            time++;
            requestAnimationFrame(draw);
        }

        if (!window.matchMedia(&#x27;(prefers-reduced-motion: reduce)&#x27;).matches) {
            draw();
        } else {
            &#x2F;&#x2F; Static version
            const nodes = getNodePositions();
            nodes.forEach(node =&gt; {
                ctx.fillStyle = node.color;
                ctx.beginPath();
                ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
                ctx.fill();

                ctx.fillStyle = colors.text;
                ctx.font = &#x27;10px JetBrains Mono&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.fillText(node.label, node.x, node.y + node.radius + 14);
            });
        }
    }

    if (document.readyState === &#x27;loading&#x27;) {
        document.addEventListener(&#x27;DOMContentLoaded&#x27;, initTree);
    } else {
        initTree();
    }
})();
&lt;&#x2F;script&gt;

&lt;style&gt;
.tree-container {
    background: var(--bg-0);
    border: 1px solid var(--divider-color);
    border-radius: 12px;
    padding: 1rem;
    margin: 1.5rem 0;
    position: relative;
}

.tree-canvas {
    width: 100%;
    height: 320px;
    display: block;
}

@media (max-width: 768px) {
    .tree-container {
        overflow-x: auto;
    }

    .tree-canvas {
        min-width: 500px;
    }
}
&lt;&#x2F;style&gt;
&lt;p&gt;Armado con este conocimiento, construí mi primer prototipo. Funcionó—más o menos. Los commands se ejecutaron. Los agentes se spawnearon. Y entonces todo empezó a romperse de formas que la documentación no me preparó.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;acto-ii-el-descenso&quot;&gt;Acto II: El Descenso&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;punto-de-dolor-1-el-bug-de-acceso-a-herramientas-mcp&quot;&gt;Punto de Dolor #1: El Bug de Acceso a Herramientas MCP&lt;&#x2F;h3&gt;
&lt;p&gt;Mi plugin agent-team-creator necesitaba integrarse con Jira. El plugin MCP de Atlassian estaba instalado y funcionando perfectamente en la sesión principal de Claude Code. Siguiendo la documentación, configuré mi agente de plugin para acceder a estas herramientas MCP.&lt;&#x2F;p&gt;
&lt;p&gt;El error fue inmediato y confuso:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Error: No such tool available: mcp__plugin_atlassian__getJiraIssue
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Pasé horas depurando. ¿Estaba mal mi configuración? ¿Nombré mal la herramienta? Entonces los encontré—cuatro issues de GitHub documentando el mismo problema:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Issue&lt;&#x2F;th&gt;&lt;th&gt;Descripción&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;#13605&lt;&#x2F;td&gt;&lt;td&gt;Los subagentes de plugin personalizados no pueden acceder a herramientas MCP&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;#15810&lt;&#x2F;td&gt;&lt;td&gt;Los subagentes no heredan herramientas MCP de agentes definidos en plugins&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;#14496&lt;&#x2F;td&gt;&lt;td&gt;Acceso inconsistente a MCP con prompts complejos&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;#7296&lt;&#x2F;td&gt;&lt;td&gt;Fallo de herencia de scope para agentes lanzados con Task&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;La documentación decía:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Cuando el campo tools se omite, los subagentes heredan todas las herramientas MCP disponibles para el hilo principal.”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;La realidad discrepaba. Los agentes definidos en plugins viven en un scope diferente—pueden ver las herramientas MCP listadas en la sesión principal, pero no pueden invocarlas.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;★ Momento de Enseñanza: La Realidad del Scope MCP&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Las herramientas MCP funcionan confiablemente en dos contextos:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;La sesión principal de Claude Code&lt;&#x2F;li&gt;
&lt;li&gt;Commands (que corren en el scope de la sesión principal)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Las herramientas MCP &lt;strong&gt;no funcionan&lt;&#x2F;strong&gt; en:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Agentes definidos en plugins spawneados via herramienta Task&lt;&#x2F;li&gt;
&lt;li&gt;Subagentes de cualquier tipo&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Si tu plugin necesita acceso a servicios externos, tus &lt;strong&gt;commands&lt;&#x2F;strong&gt; deben manejarlo, no tus agentes.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;punto-de-dolor-2-infierno-de-sincronizacion-en-tres-ubicaciones&quot;&gt;Punto de Dolor #2: Infierno de Sincronización en Tres Ubicaciones&lt;&#x2F;h3&gt;
&lt;p&gt;Después de modificar mis definiciones de agentes, recargué Claude Code. Mis cambios no estaban ahí. Edité de nuevo. Todavía nada.&lt;&#x2F;p&gt;
&lt;p&gt;Resulta que los plugins de Claude Code existen en tres ubicaciones separadas que deben sincronizarse manualmente:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Ubicación&lt;&#x2F;th&gt;&lt;th&gt;Ruta&lt;&#x2F;th&gt;&lt;th&gt;Propósito&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Fuente Marketplace&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;~&#x2F;.claude&#x2F;local-marketplace&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Donde editas&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Plugin Instalado&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;~&#x2F;.claude&#x2F;plugins&#x2F;plugin-name&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Donde Claude lee&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Cache&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;~&#x2F;.claude&#x2F;plugins&#x2F;cache&#x2F;marketplace&#x2F;plugin&#x2F;version&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Backup versionado&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;No hay hot reload. No hay auto-sync. Editas en un lugar, pero Claude lee de otro.&lt;&#x2F;p&gt;
&lt;p&gt;¿La solución? Un script de sincronización:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;PLUGIN_NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;agent-team-creator&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;MARKETPLACE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.claude&#x2F;local-marketplace&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;INSTALLED&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.claude&#x2F;plugins&#x2F;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;PLUGIN_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;CACHE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.claude&#x2F;plugins&#x2F;cache&#x2F;local-marketplace&#x2F;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;PLUGIN_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;1.0.0&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rsync&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;av&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;MARKETPLACE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;commands&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;INSTALLED&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;commands&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rsync&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;av&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;MARKETPLACE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;commands&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;CACHE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;commands&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rsync&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;av&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;MARKETPLACE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;agents&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;INSTALLED&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;agents&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rsync&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;av&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;MARKETPLACE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;agents&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;CACHE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;agents&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Plugin sincronizado en todas las ubicaciones&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Después de cada cambio: sync, cerrar Claude Code, reiniciar. Esto se volvió memoria muscular.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;★ Momento de Enseñanza: Depurando Tu Plugin&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Cuando las cosas van mal, estos comandos son tus amigos:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Verificar si el plugin está cargado&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ls&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.claude&#x2F;plugins&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Verificar sincronización del cache&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;diff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;r&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.claude&#x2F;plugins&#x2F;agent-team-creator&#x2F; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;        &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.claude&#x2F;plugins&#x2F;cache&#x2F;local-marketplace&#x2F;agent-team-creator&#x2F;1.0.0&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Validar sintaxis de marketplace.json&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.claude&#x2F;local-marketplace&#x2F;.claude-plugin&#x2F;marketplace.json&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;jq&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; .&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Ver estructura del plugin&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;tree&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.claude&#x2F;plugins&#x2F;agent-team-creator&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;punto-de-dolor-3-problemas-de-validacion-de-schema&quot;&gt;Punto de Dolor #3: Problemas de Validación de Schema&lt;&#x2F;h3&gt;
&lt;p&gt;Mi primer marketplace.json fue rechazado con errores crípticos:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;owner: Expected object, received string
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;source: Invalid input
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;El schema es estricto y poco documentado. Esto es lo que funciona:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json z-code&quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;$schema&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;https:&#x2F;&#x2F;anthropic.com&#x2F;claude-code&#x2F;marketplace.schema.json&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;local-marketplace&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;description&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Plugins locales para Claude Code&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;owner&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Tu Nombre&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;email&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;tu@email.com&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;plugins&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;    &lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;plugin-name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;description&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Descripción del plugin&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;version&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;1.0.0&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;author&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Nombre del Autor&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;email&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;author@email.com&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;source&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;.&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;category&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;development&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Trampas clave:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;owner&lt;&#x2F;code&gt; debe ser un objeto con &lt;code&gt;name&lt;&#x2F;code&gt; y &lt;code&gt;email&lt;&#x2F;code&gt;, no un string&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;source&lt;&#x2F;code&gt; debe ser &lt;code&gt;&quot;.&#x2F;&quot;&lt;&#x2F;code&gt; con la barra diagonal&lt;&#x2F;li&gt;
&lt;li&gt;Faltar cualquier campo requerido causa fallos silenciosos&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;acto-iii-el-descubrimiento&quot;&gt;Acto III: El Descubrimiento&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;la-brecha-documentacion-vs-realidad&quot;&gt;La Brecha Documentación vs. Realidad&lt;&#x2F;h3&gt;
&lt;p&gt;El punto de quiebre llegó cuando construí una arquitectura multi-agente completa basada en comportamiento documentado—solo para que fallara completamente.&lt;&#x2F;p&gt;
&lt;p&gt;Los docs prometían:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Herramientas MCP: Los subagentes pueden acceder a herramientas MCP de servidores MCP configurados.”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Probé extensivamente. Los subagentes definidos en plugins &lt;strong&gt;no pueden&lt;&#x2F;strong&gt; acceder a herramientas MCP. Esto no es un problema de configuración—es un bug conocido rastreado en múltiples issues de GitHub.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;La lección&lt;&#x2F;strong&gt;: La documentación representa comportamiento &lt;em&gt;intencionado&lt;&#x2F;em&gt;, no comportamiento &lt;em&gt;garantizado&lt;&#x2F;em&gt;. Siempre valida suposiciones empíricamente antes de construir arquitecturas dependientes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;el-muro-del-anidamiento&quot;&gt;El Muro del Anidamiento&lt;&#x2F;h3&gt;
&lt;p&gt;Mi diseño original tenía agentes spawneando sub-agentes especializados en una estructura de árbol recursivo. Elegante en teoría. Imposible en práctica.&lt;&#x2F;p&gt;
&lt;p&gt;Cuando intenté:&lt;&#x2F;p&gt;





&lt;div class=&quot;blocked-flow-container&quot; id=&quot;blocked-&quot;&gt;
    &lt;canvas class=&quot;blocked-flow-canvas&quot; aria-label=&quot;Flow diagram with blocked step&quot;&gt;&lt;&#x2F;canvas&gt;
&lt;&#x2F;div&gt;

&lt;script&gt;
(function() {
    const containerId = &#x27;blocked-&#x27;;
    const nodeNames = [&#x27;Usuario&#x27;, &#x27;Command&#x27;, &#x27;Agente&#x27;, &#x27;SubAgente&#x27;];
    const blockedName = &#x27;SubSubAgente&#x27;;

    function initBlockedFlow() {
        const container = document.getElementById(containerId);
        if (!container) return;

        const canvas = container.querySelector(&#x27;.blocked-flow-canvas&#x27;);
        const ctx = canvas.getContext(&#x27;2d&#x27;);

        let particles = [];
        let time = 0;
        let pulsePhase = 0;

        const colors = {
            nodes: [&#x27;#ff0080&#x27;, &#x27;#00d4ff&#x27;, &#x27;#00ff88&#x27;, &#x27;#8b5cf6&#x27;],
            blocked: &#x27;#ff4444&#x27;,
            blockedBg: &#x27;#442222&#x27;,
            particle: &#x27;#00ff88&#x27;,
            connection: &#x27;rgba(0, 212, 255, 0.4)&#x27;,
            blockedConnection: &#x27;rgba(255, 68, 68, 0.5)&#x27;,
            text: &#x27;#e0e0e4&#x27;
        };

        function resize() {
            const rect = container.getBoundingClientRect();
            canvas.width = rect.width;
            canvas.height = 180;
        }
        resize();
        window.addEventListener(&#x27;resize&#x27;, resize);

        function getNodePositions() {
            const allNodes = [...nodeNames, blockedName];
            const margin = 60;
            const spacing = (canvas.width - margin * 2) &#x2F; (allNodes.length - 1);
            const y = canvas.height &#x2F; 2;

            return allNodes.map((name, i) =&gt; ({
                label: name,
                x: margin + i * spacing,
                y: y,
                radius: 26,
                isBlocked: i === allNodes.length - 1,
                color: i &lt; nodeNames.length ? colors.nodes[i % colors.nodes.length] : colors.blockedBg
            }));
        }

        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            const nodes = getNodePositions();

            pulsePhase += 0.05;

            &#x2F;&#x2F; Draw connections
            for (let i = 0; i &lt; nodes.length - 1; i++) {
                const from = nodes[i];
                const to = nodes[i + 1];
                const isBlockedConnection = to.isBlocked;

                ctx.beginPath();
                ctx.moveTo(from.x + from.radius, from.y);
                ctx.lineTo(to.x - to.radius, to.y);

                if (isBlockedConnection) {
                    ctx.strokeStyle = colors.blockedConnection;
                    ctx.setLineDash([8, 4]);
                } else {
                    ctx.strokeStyle = colors.connection;
                    ctx.setLineDash([]);
                }
                ctx.lineWidth = 3;
                ctx.stroke();
                ctx.setLineDash([]);

                &#x2F;&#x2F; Arrow
                if (!isBlockedConnection) {
                    const midX = (from.x + to.x) &#x2F; 2;
                    ctx.fillStyle = colors.connection;
                    ctx.beginPath();
                    ctx.moveTo(midX - 5, from.y - 6);
                    ctx.lineTo(midX + 8, from.y);
                    ctx.lineTo(midX - 5, from.y + 6);
                    ctx.closePath();
                    ctx.fill();
                }
            }

            &#x2F;&#x2F; Draw &quot;BLOCKED&quot; label on the blocked connection
            const lastNormal = nodes[nodes.length - 2];
            const blocked = nodes[nodes.length - 1];
            const midX = (lastNormal.x + blocked.x) &#x2F; 2;

            ctx.save();
            ctx.fillStyle = colors.blocked;
            ctx.font = &#x27;bold 11px JetBrains Mono&#x27;;
            ctx.textAlign = &#x27;center&#x27;;

            &#x2F;&#x2F; Pulsing X
            const pulse = Math.sin(pulsePhase) * 0.3 + 1;
            ctx.font = `bold ${14 * pulse}px JetBrains Mono`;
            ctx.fillText(&#x27;❌&#x27;, midX, nodes[0].y - 20);

            ctx.font = &#x27;bold 10px JetBrains Mono&#x27;;
            ctx.fillText(&#x27;BLOCKED&#x27;, midX, nodes[0].y + 32);
            ctx.restore();

            &#x2F;&#x2F; Draw nodes
            nodes.forEach((node, i) =&gt; {
                if (node.isBlocked) {
                    &#x2F;&#x2F; Blocked node - pulsing red border
                    ctx.shadowColor = colors.blocked;
                    ctx.shadowBlur = 10 + Math.sin(pulsePhase) * 5;

                    ctx.fillStyle = node.color;
                    ctx.beginPath();
                    ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
                    ctx.fill();

                    ctx.strokeStyle = colors.blocked;
                    ctx.lineWidth = 3;
                    ctx.setLineDash([4, 4]);
                    ctx.stroke();
                    ctx.setLineDash([]);

                    ctx.shadowBlur = 0;

                    &#x2F;&#x2F; Strikethrough effect
                    ctx.strokeStyle = colors.blocked;
                    ctx.lineWidth = 2;
                    ctx.beginPath();
                    ctx.moveTo(node.x - node.radius + 5, node.y - node.radius + 5);
                    ctx.lineTo(node.x + node.radius - 5, node.y + node.radius - 5);
                    ctx.stroke();
                } else {
                    &#x2F;&#x2F; Normal node
                    ctx.shadowColor = node.color;
                    ctx.shadowBlur = 15;

                    ctx.fillStyle = node.color;
                    ctx.beginPath();
                    ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
                    ctx.fill();

                    ctx.shadowBlur = 0;

                    ctx.strokeStyle = &#x27;#00ff88&#x27;;
                    ctx.lineWidth = 2;
                    ctx.stroke();
                }

                &#x2F;&#x2F; Label
                ctx.fillStyle = node.isBlocked ? &#x27;#666&#x27; : &#x27;#0a0a0f&#x27;;
                ctx.font = &#x27;bold 10px JetBrains Mono&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.textBaseline = &#x27;middle&#x27;;

                &#x2F;&#x2F; Wrap text if needed
                const words = node.label.split(&#x2F;(?=[A-Z])&#x2F;);
                if (words.length &gt; 1 &amp;&amp; node.label.length &gt; 8) {
                    ctx.fillText(words[0], node.x, node.y - 6);
                    ctx.fillText(words.slice(1).join(&#x27;&#x27;), node.x, node.y + 6);
                } else {
                    ctx.fillText(node.label, node.x, node.y);
                }
            });

            &#x2F;&#x2F; Particles (only on valid connections)
            particles.forEach(p =&gt; {
                p.progress += p.speed;
                if (p.progress &gt;= 1) {
                    p.segmentIndex++;
                    p.progress = 0;
                    if (p.segmentIndex &gt;= nodes.length - 2) {
                        p.segmentIndex = 0;
                    }
                }

                const from = nodes[p.segmentIndex];
                const to = nodes[p.segmentIndex + 1];

                if (from &amp;&amp; to &amp;&amp; !to.isBlocked) {
                    const ease = p.progress * p.progress * (3 - 2 * p.progress);
                    const x = from.x + (to.x - from.x) * ease;
                    const y = from.y + (to.y - from.y) * ease;

                    ctx.fillStyle = colors.particle;
                    ctx.shadowColor = colors.particle;
                    ctx.shadowBlur = 10;
                    ctx.beginPath();
                    ctx.arc(x, y, 4, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.shadowBlur = 0;
                }
            });

            time++;
            requestAnimationFrame(draw);
        }

        &#x2F;&#x2F; Initialize particles
        for (let i = 0; i &lt; 2; i++) {
            particles.push({
                segmentIndex: i,
                progress: 0,
                speed: 0.015
            });
        }

        if (!window.matchMedia(&#x27;(prefers-reduced-motion: reduce)&#x27;).matches) {
            draw();
        } else {
            &#x2F;&#x2F; Static version
            const nodes = getNodePositions();
            nodes.forEach(node =&gt; {
                ctx.fillStyle = node.color;
                ctx.beginPath();
                ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
                ctx.fill();

                ctx.fillStyle = node.isBlocked ? &#x27;#666&#x27; : &#x27;#0a0a0f&#x27;;
                ctx.font = &#x27;bold 10px JetBrains Mono&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.fillText(node.label, node.x, node.y);
            });
        }
    }

    if (document.readyState === &#x27;loading&#x27;) {
        document.addEventListener(&#x27;DOMContentLoaded&#x27;, initBlockedFlow);
    } else {
        initBlockedFlow();
    }
})();
&lt;&#x2F;script&gt;

&lt;style&gt;
.blocked-flow-container {
    background: var(--bg-0);
    border: 1px solid var(--divider-color);
    border-radius: 12px;
    padding: 1rem;
    margin: 1.5rem 0;
    position: relative;
}

.blocked-flow-canvas {
    width: 100%;
    height: 180px;
    display: block;
}

@media (max-width: 768px) {
    .blocked-flow-container {
        overflow-x: auto;
    }

    .blocked-flow-canvas {
        min-width: 500px;
    }
}
&lt;&#x2F;style&gt;
&lt;p&gt;Claude Code respondió:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Error: Subagents cannot spawn subagents
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Este es un límite duro de la plataforma. Solo un nivel de anidamiento. La restricción existe por buenas razones—prevenir recursión infinita, mantener consumo de recursos acotado, asegurar ejecución predecible. Pero invalidó toda mi arquitectura.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;herencia-de-modelo-que-no-hereda&quot;&gt;Herencia de Modelo que No Hereda&lt;&#x2F;h3&gt;
&lt;p&gt;Configuré mis agentes para usar &lt;code&gt;model: inherit&lt;&#x2F;code&gt;, esperando que usaran cualquier modelo que usara la sesión padre. Cada subagente usó por defecto Sonnet 4, sin importar:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Modelo padre&lt;&#x2F;li&gt;
&lt;li&gt;Configuración global&lt;&#x2F;li&gt;
&lt;li&gt;Configuración local&lt;&#x2F;li&gt;
&lt;li&gt;Configuración explícita del agente&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Otro descubrimiento: Claude Code infiere comportamiento del agente a partir del nombre. Un agente llamado “code-reviewer” activa comportamientos de revisión built-in que pueden sobrescribir tus instrucciones personalizadas. Nombrar no es solo etiquetar—es funcional.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;acto-iv-la-solucion&quot;&gt;Acto IV: La Solución&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;el-patron-de-arquitectura-hibrida&quot;&gt;El Patrón de Arquitectura Híbrida&lt;&#x2F;h3&gt;
&lt;p&gt;Las restricciones crían creatividad. Enfrentando bugs de acceso MCP, límites de anidamiento, y fallos de herencia de modelo, desarrollé lo que ahora llamo el &lt;strong&gt;Patrón de Arquitectura Híbrida&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;La insight central: &lt;strong&gt;Commands y Agents tienen capacidades diferentes. Usa cada uno para lo que hace bien.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Capa de Command (I&#x2F;O)&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Acceso a herramientas MCP (funciona confiablemente)&lt;&#x2F;li&gt;
&lt;li&gt;Operaciones de sistema de archivos&lt;&#x2F;li&gt;
&lt;li&gt;Interacción con usuario (AskUserQuestion)&lt;&#x2F;li&gt;
&lt;li&gt;Caché de respuestas&lt;&#x2F;li&gt;
&lt;li&gt;Comunicación con servicios externos&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Capa de Agent (Inteligencia)&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Razonamiento y análisis puro&lt;&#x2F;li&gt;
&lt;li&gt;Formateo de contenido&lt;&#x2F;li&gt;
&lt;li&gt;Toma de decisiones&lt;&#x2F;li&gt;
&lt;li&gt;Reconocimiento de patrones&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Sin dependencias directas de I&#x2F;O&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Los commands se convierten en adaptadores de I&#x2F;O. Los agentes se convierten en motores de razonamiento. Ninguno intenta hacer el trabajo del otro.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;el-pipeline-de-6-fases&quot;&gt;El Pipeline de 6 Fases&lt;&#x2F;h3&gt;
&lt;p&gt;Así es como esto se manifiesta en mi comando &lt;code&gt;&#x2F;generate-jira-task&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;



&lt;div class=&quot;pipeline-container&quot; id=&quot;pipeline&quot;&gt;
    &lt;canvas class=&quot;pipeline-canvas&quot; aria-label=&quot;Pipeline flow visualization&quot;&gt;&lt;&#x2F;canvas&gt;
    &lt;div class=&quot;pipeline-legend&quot;&gt;
        &lt;span class=&quot;legend-item&quot;&gt;&lt;span class=&quot;legend-dot command&quot;&gt;&lt;&#x2F;span&gt; Command (I&#x2F;O)&lt;&#x2F;span&gt;
        &lt;span class=&quot;legend-item&quot;&gt;&lt;span class=&quot;legend-dot agent&quot;&gt;&lt;&#x2F;span&gt; Agent (Intelligence)&lt;&#x2F;span&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;

&lt;script&gt;
(function() {
    const containerId = &#x27;pipeline&#x27;;
    const phasesData = [
    {&quot;phase&quot;: 0, &quot;owner&quot;: &quot;Command&quot;, &quot;label&quot;: &quot;Verificar MCP&quot;, &quot;io&quot;: &quot;external&quot;},
    {&quot;phase&quot;: 1, &quot;owner&quot;: &quot;Command&quot;, &quot;label&quot;: &quot;Resolver Proyecto&quot;, &quot;io&quot;: &quot;external&quot;},
    {&quot;phase&quot;: 2, &quot;owner&quot;: &quot;Command&quot;, &quot;label&quot;: &quot;Cargar Informe&quot;, &quot;io&quot;: &quot;local&quot;},
    {&quot;phase&quot;: 3, &quot;owner&quot;: &quot;Command&quot;, &quot;label&quot;: &quot;Verificar Dups&quot;, &quot;io&quot;: &quot;external&quot;},
    {&quot;phase&quot;: 4, &quot;owner&quot;: &quot;Agent&quot;, &quot;label&quot;: &quot;Razonamiento&quot;, &quot;io&quot;: &quot;none&quot;},
    {&quot;phase&quot;: 5, &quot;owner&quot;: &quot;Agent&quot;, &quot;label&quot;: &quot;Formateo&quot;, &quot;io&quot;: &quot;none&quot;},
    {&quot;phase&quot;: 6, &quot;owner&quot;: &quot;Command&quot;, &quot;label&quot;: &quot;Salida&quot;, &quot;io&quot;: &quot;external&quot;}
];

    function initPipeline() {
        const container = document.getElementById(containerId);
        if (!container) return;

        const canvas = container.querySelector(&#x27;.pipeline-canvas&#x27;);
        const ctx = canvas.getContext(&#x27;2d&#x27;);

        &#x2F;&#x2F; Responsive sizing
        function resize() {
            const rect = container.getBoundingClientRect();
            canvas.width = rect.width;
            canvas.height = 180;
        }
        resize();
        window.addEventListener(&#x27;resize&#x27;, resize);

        &#x2F;&#x2F; Colors
        const colors = {
            command: &#x27;#00d4ff&#x27;,
            agent: &#x27;#00ff88&#x27;,
            external: &#x27;#8b5cf6&#x27;,
            local: &#x27;#ff8800&#x27;,
            none: &#x27;#444466&#x27;,
            particle: &#x27;#00ff88&#x27;,
            bg: &#x27;rgba(10, 10, 15, 0.8)&#x27;
        };

        &#x2F;&#x2F; Animation state
        let particles = [];
        let time = 0;

        &#x2F;&#x2F; Get phase positions
        function getPhasePositions() {
            const phases = phasesData;
            const margin = 60;
            const spacing = (canvas.width - margin * 2) &#x2F; (phases.length - 1);
            return phases.map((p, i) =&gt; ({
                ...p,
                x: margin + i * spacing,
                y: canvas.height &#x2F; 2,
                radius: 24
            }));
        }

        &#x2F;&#x2F; Create particle
        function createParticle(positions) {
            return {
                phaseIndex: 0,
                progress: 0,
                speed: 0.01 + Math.random() * 0.01,
                x: positions[0].x,
                y: positions[0].y
            };
        }

        &#x2F;&#x2F; Draw
        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            const positions = getPhasePositions();

            &#x2F;&#x2F; Draw connections
            ctx.lineWidth = 2;
            ctx.strokeStyle = &#x27;rgba(0, 212, 255, 0.3)&#x27;;
            ctx.beginPath();
            positions.forEach((pos, i) =&gt; {
                if (i === 0) ctx.moveTo(pos.x, pos.y);
                else ctx.lineTo(pos.x, pos.y);
            });
            ctx.stroke();

            &#x2F;&#x2F; Draw arrows
            for (let i = 0; i &lt; positions.length - 1; i++) {
                const from = positions[i];
                const to = positions[i + 1];
                const midX = (from.x + to.x) &#x2F; 2;
                const midY = (from.y + to.y) &#x2F; 2;

                ctx.fillStyle = &#x27;rgba(0, 212, 255, 0.5)&#x27;;
                ctx.beginPath();
                ctx.moveTo(midX - 6, midY - 4);
                ctx.lineTo(midX + 6, midY);
                ctx.lineTo(midX - 6, midY + 4);
                ctx.closePath();
                ctx.fill();
            }

            &#x2F;&#x2F; Draw phase nodes
            positions.forEach((pos, i) =&gt; {
                const isCommand = pos.owner === &#x27;Command&#x27;;
                const color = isCommand ? colors.command : colors.agent;

                &#x2F;&#x2F; Glow
                const gradient = ctx.createRadialGradient(pos.x, pos.y, 0, pos.x, pos.y, pos.radius * 2);
                gradient.addColorStop(0, color.replace(&#x27;)&#x27;, &#x27;, 0.3)&#x27;).replace(&#x27;rgb&#x27;, &#x27;rgba&#x27;));
                gradient.addColorStop(1, &#x27;transparent&#x27;);
                ctx.fillStyle = gradient;
                ctx.beginPath();
                ctx.arc(pos.x, pos.y, pos.radius * 2, 0, Math.PI * 2);
                ctx.fill();

                &#x2F;&#x2F; Node
                ctx.fillStyle = color;
                ctx.beginPath();
                ctx.arc(pos.x, pos.y, pos.radius, 0, Math.PI * 2);
                ctx.fill();

                &#x2F;&#x2F; Phase number
                ctx.fillStyle = &#x27;#0a0a0f&#x27;;
                ctx.font = &#x27;bold 14px JetBrains Mono, monospace&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.textBaseline = &#x27;middle&#x27;;
                ctx.fillText(pos.phase, pos.x, pos.y);

                &#x2F;&#x2F; Label
                ctx.fillStyle = &#x27;#e0e0e4&#x27;;
                ctx.font = &#x27;11px JetBrains Mono, monospace&#x27;;
                ctx.fillText(pos.label, pos.x, pos.y + pos.radius + 16);

                &#x2F;&#x2F; I&#x2F;O indicator
                if (pos.io !== &#x27;none&#x27;) {
                    ctx.fillStyle = pos.io === &#x27;external&#x27; ? colors.external : colors.local;
                    ctx.font = &#x27;9px JetBrains Mono, monospace&#x27;;
                    ctx.fillText(pos.io.toUpperCase(), pos.x, pos.y - pos.radius - 10);
                }
            });

            &#x2F;&#x2F; Update and draw particles
            particles.forEach(p =&gt; {
                if (p.phaseIndex &gt;= positions.length - 1) {
                    p.phaseIndex = 0;
                    p.progress = 0;
                }

                const from = positions[p.phaseIndex];
                const to = positions[p.phaseIndex + 1];

                p.progress += p.speed;
                if (p.progress &gt;= 1) {
                    p.phaseIndex++;
                    p.progress = 0;
                }

                if (to) {
                    p.x = from.x + (to.x - from.x) * p.progress;
                    p.y = from.y + (to.y - from.y) * p.progress;
                }

                &#x2F;&#x2F; Draw particle
                ctx.fillStyle = colors.particle;
                ctx.beginPath();
                ctx.arc(p.x, p.y, 4, 0, Math.PI * 2);
                ctx.fill();

                &#x2F;&#x2F; Particle glow
                const pGrad = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, 12);
                pGrad.addColorStop(0, &#x27;rgba(0, 255, 136, 0.4)&#x27;);
                pGrad.addColorStop(1, &#x27;transparent&#x27;);
                ctx.fillStyle = pGrad;
                ctx.beginPath();
                ctx.arc(p.x, p.y, 12, 0, Math.PI * 2);
                ctx.fill();
            });

            time++;
            requestAnimationFrame(draw);
        }

        &#x2F;&#x2F; Initialize particles
        const positions = getPhasePositions();
        for (let i = 0; i &lt; 3; i++) {
            const p = createParticle(positions);
            p.phaseIndex = i * 2;
            particles.push(p);
        }

        &#x2F;&#x2F; Respect reduced motion
        if (!window.matchMedia(&#x27;(prefers-reduced-motion: reduce)&#x27;).matches) {
            draw();
        } else {
            &#x2F;&#x2F; Static version
            const positions = getPhasePositions();
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            ctx.lineWidth = 2;
            ctx.strokeStyle = &#x27;rgba(0, 212, 255, 0.5)&#x27;;
            ctx.beginPath();
            positions.forEach((pos, i) =&gt; {
                if (i === 0) ctx.moveTo(pos.x, pos.y);
                else ctx.lineTo(pos.x, pos.y);
            });
            ctx.stroke();

            positions.forEach((pos) =&gt; {
                const color = pos.owner === &#x27;Command&#x27; ? colors.command : colors.agent;
                ctx.fillStyle = color;
                ctx.beginPath();
                ctx.arc(pos.x, pos.y, pos.radius, 0, Math.PI * 2);
                ctx.fill();

                ctx.fillStyle = &#x27;#0a0a0f&#x27;;
                ctx.font = &#x27;bold 14px JetBrains Mono, monospace&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.textBaseline = &#x27;middle&#x27;;
                ctx.fillText(pos.phase, pos.x, pos.y);

                ctx.fillStyle = &#x27;#e0e0e4&#x27;;
                ctx.font = &#x27;11px JetBrains Mono, monospace&#x27;;
                ctx.fillText(pos.label, pos.x, pos.y + pos.radius + 16);
            });
        }
    }

    if (document.readyState === &#x27;loading&#x27;) {
        document.addEventListener(&#x27;DOMContentLoaded&#x27;, initPipeline);
    } else {
        initPipeline();
    }
})();
&lt;&#x2F;script&gt;

&lt;style&gt;
.pipeline-container {
    background: var(--bg-0);
    border: 1px solid var(--divider-color);
    border-radius: 12px;
    padding: 1.5rem 1rem 1rem;
    margin: 1.5rem 0;
    position: relative;
}

.pipeline-canvas {
    width: 100%;
    height: 180px;
    display: block;
}

.pipeline-legend {
    display: flex;
    justify-content: center;
    gap: 2rem;
    margin-top: 0.5rem;
    font-family: &#x27;JetBrains Mono&#x27;, monospace;
    font-size: 0.8rem;
    color: var(--meta-color);
}

.legend-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.legend-dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
}

.legend-dot.command {
    background: #00d4ff;
}

.legend-dot.agent {
    background: #00ff88;
}

@media (max-width: 768px) {
    .pipeline-container {
        overflow-x: auto;
    }

    .pipeline-canvas {
        min-width: 600px;
    }
}
&lt;&#x2F;style&gt;
&lt;p&gt;Los commands manejan toda la comunicación externa (nodos cyan). Los agentes manejan todo el pensamiento (nodos verdes). El límite es limpio—nota cómo las operaciones de I&#x2F;O (marcadas EXTERNAL&#x2F;LOCAL) se agrupan en la capa de Command.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;degradacion-graciosa&quot;&gt;Degradación Graciosa&lt;&#x2F;h3&gt;
&lt;p&gt;¿Qué pasa si MCP no está disponible? El patrón maneja esto elegantemente:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;FALLBACK_MODE se activa cuando:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  - Plugin MCP de Atlassian no disponible
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Acciones:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  - Saltar Fase 1 (resolución de proyecto)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  - Saltar Fase 3 (verificación de duplicados)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  - Fase 6: Output markdown a .claude&#x2F;reports&#x2F;jira-drafts&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;La capa de inteligencia (Fases 4-5) funciona idénticamente ya sea conectada a Jira o no. La capa de I&#x2F;O degrada graciosamente a output de archivo local.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;★ Momento de Enseñanza: Frontmatter de Command y Agent&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Template de Command&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-other z-document z-begin z-yaml&quot;&gt;---&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;generate-jira-task&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;description&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Generar tarea Jira desde informe de depuración&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;allowed-tools&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Read&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Write&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Glob&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Grep&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Task&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;AskUserQuestion&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;argument-hint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;[archivo-informe]&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-other z-document z-begin z-yaml&quot;&gt;---&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Template de Agent&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-other z-document z-begin z-yaml&quot;&gt;---&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;implementation-planner&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;description&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-block-scalar z-literal z-yaml&quot;&gt;|&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;  Usa este agente para analizar informes de depuración y crear planes de implementación.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;model&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;inherit&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;color&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;cyan&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;tools&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Read&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Grep&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Glob&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-other z-document z-begin z-yaml&quot;&gt;---&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Nota: Los agentes &lt;strong&gt;no&lt;&#x2F;strong&gt; deben incluir herramientas MCP en su lista de tools—no funcionarán de todos modos.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;acto-v-el-retorno&quot;&gt;Acto V: El Retorno&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;lo-que-funciona-ahora&quot;&gt;Lo Que Funciona Ahora&lt;&#x2F;h3&gt;
&lt;p&gt;El plugin agent-team-creator ahora funciona confiablemente con tres commands:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&#x2F;generate-agent-team&lt;&#x2F;code&gt; - Analiza códigos base y genera agentes especializados&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;generate-debugger&lt;&#x2F;code&gt; - Crea agentes de depuración específicos del proyecto&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;generate-jira-task&lt;&#x2F;code&gt; - Convierte informes de depuración a tareas Jira&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Cada uno sigue el Patrón de Arquitectura Híbrida. Los commands manejan I&#x2F;O. Los agentes manejan razonamiento. El sistema degrada graciosamente cuando los servicios no están disponibles.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lecciones-aprendidas&quot;&gt;Lecciones Aprendidas&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Lección&lt;&#x2F;th&gt;&lt;th&gt;Implicación&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Confía pero verifica documentación&lt;&#x2F;td&gt;&lt;td&gt;Construye pruebas mínimas de concepto antes de comprometerte con arquitecturas&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Las restricciones revelan claridad&lt;&#x2F;td&gt;&lt;td&gt;El patrón híbrido es más limpio que mi diseño original sin restricciones&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;La sincronización es tu responsabilidad&lt;&#x2F;td&gt;&lt;td&gt;Automatízala. Hazla memoria muscular.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Nombrar es funcional&lt;&#x2F;td&gt;&lt;td&gt;Los nombres de agentes influencian el comportamiento de la plataforma&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Explícito sobre implícito&lt;&#x2F;td&gt;&lt;td&gt;Nunca asumas herencia de herramientas; declara todo&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;checklist-de-inicio-rapido-para-nuevos-desarrolladores-de-plugins&quot;&gt;Checklist de Inicio Rápido para Nuevos Desarrolladores de Plugins&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Setup&lt;&#x2F;strong&gt;: Crea estructura de marketplace con schema JSON apropiado&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Desarrolla&lt;&#x2F;strong&gt;: Edita archivos solo en la fuente del marketplace&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Sync&lt;&#x2F;strong&gt;: Ejecuta script rsync después de cada cambio&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Reinicia&lt;&#x2F;strong&gt;: Cierra y reinicia Claude Code (no hay hot reload)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Prueba&lt;&#x2F;strong&gt;: Verifica disponibilidad del command con &lt;code&gt;&#x2F;help&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Depura&lt;&#x2F;strong&gt;: Usa &lt;code&gt;diff -r&lt;&#x2F;code&gt; y &lt;code&gt;jq&lt;&#x2F;code&gt; para validación&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;La lección clave: &lt;strong&gt;Commands para I&#x2F;O, Agents para razonamiento&lt;&#x2F;strong&gt;. Este patrón evita cada bug que encontré.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusión&lt;&#x2F;h2&gt;
&lt;p&gt;Construir agent-team-creator me enseñó más sobre arquitectura de agentes IA que cualquier documentación podría. Los bugs no fueron obstáculos—fueron maestros. Las restricciones no fueron limitaciones—fueron principios de diseño disfrazados.&lt;&#x2F;p&gt;
&lt;p&gt;El Patrón de Arquitectura Híbrida emergió de la necesidad, pero ahora creo que es superior a diseños sin restricciones. Límites claros entre capas de I&#x2F;O e inteligencia hacen sistemas más fáciles de probar, depurar, y extender. La degradación graciosa se vuelve natural cuando ya has separado concerns.&lt;&#x2F;p&gt;
&lt;p&gt;En la Parte 2 de esta serie, daré un paso atrás de los detalles prácticos y examinaré qué revelan estos descubrimientos sobre el diseño de frameworks de agentes más ampliamente. ¿Por qué los modelos de herencia se rompen en sistemas multi-agente? ¿Qué hace que la topología hub-and-spoke emerja naturalmente? ¿Y qué nos dice naming-as-behavior sobre sistemas IA en general?&lt;&#x2F;p&gt;
&lt;p&gt;Por ahora, si estás construyendo plugins de Claude Code: abraza las restricciones. Te enseñarán cosas que la documentación no puede.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;obten-el-plugin&quot;&gt;Obtén el Plugin&lt;&#x2F;h2&gt;
&lt;p&gt;El plugin es open source: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Cpicon&#x2F;claude-code-plugins&quot;&gt;Cpicon&#x2F;claude-code-plugins&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Usa la pestaña &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Cpicon&#x2F;claude-code-plugins&#x2F;issues&quot;&gt;GitHub Issues&lt;&#x2F;a&gt; para solicitar features, reportar bugs, o discutir mejoras.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Navegación de la Serie:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Parte 0&lt;&#x2F;strong&gt;: &lt;a href=&quot;&#x2F;posts&#x2F;claude-code-plugin-journey-part0&#x2F;&quot;&gt;Agent Team Creator&lt;&#x2F;a&gt; — Qué hace el plugin y cómo usarlo&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Parte 1&lt;&#x2F;strong&gt; (Estás aquí): Construyendo el plugin, lecciones aprendidas&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Parte 2&lt;&#x2F;strong&gt;: &lt;a href=&quot;&#x2F;posts&#x2F;claude-code-plugin-journey-part2&#x2F;&quot;&gt;La Paradoja de la Herencia&lt;&#x2F;a&gt; — Insights de investigación, patrones&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Este post está basado en observaciones empíricas de construir el plugin agent-team-creator. Todos los puntos de dolor y soluciones fueron documentados a través de sesiones reales de desarrollo.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        <summary type="html">El Patrón de Arquitectura Híbrida: Lecciones de agent-team-creator

Esta es la Parte 1 de una serie de tres partes. Comienza con Parte 0: Agent Team Creator para ver qué hace el plugin, o continúa aquí para el viaje de desarrollo.

Pensé que construir un plugin de Claude Code tomaría un fin de semana. Tres días después de luchar con bugs de acceso a herramientas MCP, sincronización de archivos en tres ubicaciones, y documentación que prometía features que no funcionaban, me di cuenta de que estaba construyendo algo más valioso que un plugin—estaba mapeando territorio inexplorado.
Esta es la historia de construir agent-team-creator, un plugin de Claude Code que analiza códigos base y genera agentes IA específicos del proyecto. En el camino, descubrí un patrón que convirtió las limitaciones de la plataforma en claridad arquitectónica: el Patrón de Arquitectura Híbrida.
…</summary>
        </entry><entry xml:lang="es">
        <title>Claude Code Plugin Journey Parte 0: Agent Team Creator</title>
        <published>2026-01-06T10:00:00+00:00</published>
        <updated>2026-01-06T10:00:00+00:00</updated>
        <author>
            <name>Christian Picon Calderon</name>
        </author>
        <link rel="alternate" href="https://futurewithml.netlify.app/es/posts/claude-code-plugin-journey-part0/" type="text/html"/>
        <id>https://futurewithml.netlify.app/es/posts/claude-code-plugin-journey-part0/</id>
        
            <content type="html">&lt;h1 id=&quot;claude-code-plugin-journey-parte-0-agent-team-creator&quot;&gt;Claude Code Plugin Journey Parte 0: Agent Team Creator&lt;&#x2F;h1&gt;
&lt;p&gt;¿Qué pasaría si pudieras apuntar una IA a tu proyecto y hacer que genere especialistas que realmente entienden tu stack? No asistentes genéricos—agentes que conocen tu arquitectura, tus patrones, tus convenciones.&lt;&#x2F;p&gt;
&lt;p&gt;Eso es lo que hace &lt;code&gt;agent-team-creator&lt;&#x2F;code&gt;. Déjame mostrarte el flujo de trabajo.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;escenario-1-genera-tu-equipo-de-agentes&quot;&gt;Escenario 1: Genera tu Equipo de Agentes&lt;&#x2F;h2&gt;
&lt;p&gt;Comienzas un nuevo proyecto—o te unes a uno existente. El código base es desconocido. Necesitas ayuda, pero los consejos genéricos de IA no son suficientes.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Paso 1: Genera tu equipo de agentes&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;generate-agent-team
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Observa cómo el plugin analiza tu proyecto:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Analizando código base...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Lenguajes: Python (75%), TypeScript (20%), SQL (5%)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Frameworks: FastAPI, React, SQLAlchemy
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Arquitectura: Monorepo con separación backend&#x2F;frontend
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Patrones: Patrón repository, inyección de dependencias
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Generando agentes especializados...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;✓ fastapi-expert
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Conoce: Tus patrones de endpoints, modelos Pydantic, stack de middleware
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;✓ react-specialist
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Conoce: Tu librería de componentes, gestión de estado, patrones de hooks
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;✓ database-architect
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Conoce: Tus modelos SQLAlchemy, patrones de migración, convenciones de consultas
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;✓ test-strategist
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Conoce: Tus fixtures de pytest, patrones de mocking, utilidades de testing
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Equipo guardado en .claude&#x2F;agents&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Paso 2: Usa tus agentes inmediatamente&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Ahora tienes especialistas conscientes del proyecto. Así es como usarlos:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Pregunta sobre arquitectura:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Usa el agente fastapi-expert para explicar cómo funciona
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;la autenticación en este proyecto
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Implementa una funcionalidad:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Usa el agente react-specialist para ayudarme a añadir un nuevo
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;componente de dashboard siguiendo nuestros patrones existentes
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Depura un problema:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Usa el agente database-architect para ayudarme a entender por qué
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;esta consulta es lenta - revisa src&#x2F;repositories&#x2F;user_repo.py
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Escribe tests:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Usa el agente test-strategist para escribir tests de integración para
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;el nuevo endpoint de pagos siguiendo nuestras convenciones de testing
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;¿La diferencia?&lt;&#x2F;strong&gt; Estos agentes no dan consejos genéricos. Referencian &lt;em&gt;tus&lt;&#x2F;em&gt; archivos, &lt;em&gt;tus&lt;&#x2F;em&gt; patrones, &lt;em&gt;tus&lt;&#x2F;em&gt; convenciones.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;escenario-2-flujo-de-trabajo-avanzado-de-depuracion&quot;&gt;Escenario 2: Flujo de Trabajo Avanzado de Depuración&lt;&#x2F;h2&gt;
&lt;p&gt;Después de generar tu equipo de agentes, puedes crear un &lt;strong&gt;Project Debugger&lt;&#x2F;strong&gt;—un orquestador que coordina a tus especialistas para diagnosticar problemas complejos.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Paso 1: Genera el Project Debugger&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;generate-debugger
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Descubriendo agentes del proyecto...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Encontrados: fastapi-expert, react-specialist, database-architect, test-strategist
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Analizando arquitectura del proyecto...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Puntos de entrada identificados
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Patrones de manejo de errores mapeados
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Convenciones de logging detectadas
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Generando project-debugger.md...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;✓ Creado: .claude&#x2F;agents&#x2F;project-debugger.md
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  - Orquesta tus 4 agentes especialistas
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  - Produce informes de depuración estructurados
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  - Identifica causas raíz con referencias archivo:línea
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Paso 2: Usa el Debugger para investigar&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Cuando encuentres un bug, invoca el project debugger:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Usa el agente project-debugger para investigar: Los usuarios están
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;recibiendo errores 500 cuando envían el formulario de checkout
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;El debugger orquesta a tus especialistas:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Consultando fastapi-expert...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Trazado flujo de request a través de api&#x2F;routes&#x2F;checkout.py
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Encontrado: PaymentService.process() lanza excepción no manejada
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Consultando database-architect...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Verificado manejo de transacciones en repositories&#x2F;order_repo.py
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Encontrado: Falta rollback en fallo de pago
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Consultando test-strategist...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Revisada cobertura de tests para flujo de checkout
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Encontrado: No hay test para escenario de fallo de pago
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Generando informe de depuración...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Paso 3: Genera un informe de depuración&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;El debugger produce un informe estructurado guardado en &lt;code&gt;.claude&#x2F;reports&#x2F;debugging&#x2F;&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;markdown&quot; class=&quot;language-markdown z-code&quot;&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-block-level z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-heading z-1 z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-begin z-markdown&quot;&gt;#&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-heading z-1 z-markdown&quot;&gt;&lt;span class=&quot;z-entity z-name z-section z-markdown&quot;&gt;Informe de Depuración: Errores 500 en Checkout&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-whitespace z-newline z-markdown&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-block-level z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-heading z-2 z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-begin z-markdown&quot;&gt;##&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-heading z-2 z-markdown&quot;&gt;&lt;span class=&quot;z-entity z-name z-section z-markdown&quot;&gt;Causa Raíz&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-whitespace z-newline z-markdown&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-markdown&quot;&gt;Falta manejo de excepciones en PaymentService.process()
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-markdown&quot;&gt;(src&#x2F;services&#x2F;payment.py:45) combinado con falta de
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-markdown&quot;&gt;rollback de transacción (src&#x2F;repositories&#x2F;order_repo.py:78)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-markdown&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-block-level z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-heading z-2 z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-begin z-markdown&quot;&gt;##&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-heading z-2 z-markdown&quot;&gt;&lt;span class=&quot;z-entity z-name z-section z-markdown&quot;&gt;Evidencia&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-whitespace z-newline z-markdown&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-list z-unnumbered z-bullet z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list_item z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-list z-unnumbered z-markdown&quot;&gt; &lt;span class=&quot;z-meta z-paragraph z-list z-markdown&quot;&gt;Archivo: src&#x2F;services&#x2F;payment.py:45-52
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-list z-unnumbered z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-list z-markdown&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-list z-unnumbered z-bullet z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list_item z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-list z-unnumbered z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-list z-markdown&quot;&gt; Archivo: src&#x2F;repositories&#x2F;order_repo.py:78-85
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-list z-unnumbered z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-list z-markdown&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-list z-unnumbered z-bullet z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list_item z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-list z-unnumbered z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-list z-markdown&quot;&gt; Test faltante: tests&#x2F;integration&#x2F;test_checkout.py
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-list z-unnumbered z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-list z-markdown&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-list z-unnumbered z-markdown&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-list z-unnumbered z-markdown&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block-level z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-heading z-2 z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-begin z-markdown&quot;&gt;##&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-heading z-2 z-markdown&quot;&gt;&lt;span class=&quot;z-entity z-name z-section z-markdown&quot;&gt;Corrección Recomendada&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-whitespace z-newline z-markdown&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-list z-numbered z-bullet z-markdown&quot;&gt;1&lt;span class=&quot;z-punctuation z-definition z-list_item z-markdown&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-list z-numbered z-markdown&quot;&gt; &lt;span class=&quot;z-meta z-paragraph z-list z-markdown&quot;&gt;Añadir try&#x2F;except en payment.py:45
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-list z-numbered z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-list z-markdown&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-list z-numbered z-bullet z-markdown&quot;&gt;2&lt;span class=&quot;z-punctuation z-definition z-list_item z-markdown&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-list z-numbered z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-list z-markdown&quot;&gt; Implementar rollback en order_repo.py:78
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-list z-numbered z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-list z-markdown&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-list z-numbered z-bullet z-markdown&quot;&gt;3&lt;span class=&quot;z-punctuation z-definition z-list_item z-markdown&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-list z-numbered z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-list z-markdown&quot;&gt; Añadir test de escenario de fallo
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-list z-numbered z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-list z-markdown&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-list z-numbered z-markdown&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-list z-numbered z-markdown&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block-level z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-heading z-2 z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-begin z-markdown&quot;&gt;##&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-heading z-2 z-markdown&quot;&gt;&lt;span class=&quot;z-entity z-name z-section z-markdown&quot;&gt;Efectos Secundarios&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-whitespace z-newline z-markdown&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-list z-unnumbered z-bullet z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list_item z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-list z-unnumbered z-markdown&quot;&gt; &lt;span class=&quot;z-meta z-paragraph z-list z-markdown&quot;&gt;Los pedidos pueden estar en estado inconsistente (necesita migración)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Paso 4: Crea un ticket de Jira desde el informe&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Ahora convierte ese informe en una tarea de Jira. El comando encuentra automáticamente el informe de depuración más reciente:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;generate-jira-task
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Buscando último informe de depuración...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Encontrado: .claude&#x2F;reports&#x2F;debugging&#x2F;report-2026-01-06-1430.md
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Cargando informe de depuración...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Buscando issues similares...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Buscando: &amp;quot;checkout payment exception rollback&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── Encontrados 2 issues potencialmente relacionados:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  PROJ-234: &amp;quot;Payment processing timeout errors&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;           Estado: En Progreso
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  PROJ-189: &amp;quot;Checkout form validation issues&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;           Estado: Hecho
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;¿Cómo deseas proceder?
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&amp;gt; Crear nueva tarea de todos modos
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&amp;gt; Abortar - Actualizaré un issue existente
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Si eliges crear una nueva tarea:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Creando issue de Jira...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;✓ Creado: PROJ-456 &amp;quot;Fix checkout 500 errors: missing exception handling&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  https:&#x2F;&#x2F;yourcompany.atlassian.net&#x2F;browse&#x2F;PROJ-456
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;La verificación de duplicados previene llenar tu backlog con issues relacionados. Si el bug es una variante de un issue existente, puedes actualizar ese ticket en lugar de crear uno nuevo.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;¿No tienes Jira configurado?&lt;&#x2F;strong&gt; El comando degrada gracefully a generar un archivo markdown listo para copiar en &lt;code&gt;.claude&#x2F;reports&#x2F;jira-drafts&#x2F;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;escenario-3-flujo-de-trabajo-repetible-para-multiples-bugs&quot;&gt;Escenario 3: Flujo de Trabajo Repetible para Múltiples Bugs&lt;&#x2F;h2&gt;
&lt;p&gt;Cada investigación de bug crea su propio informe de depuración, que lleva a su propio ticket de Jira. Así es como el flujo escala a través de múltiples issues:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Lunes: Problema de rendimiento de API&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Usa el agente project-debugger para investigar: ¿Por qué están
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;subiendo los tiempos de respuesta de la API durante horas pico?
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Informe guardado: &lt;code&gt;.claude&#x2F;reports&#x2F;debugging&#x2F;report-2026-01-06-0900.md&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;generate-jira-task
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Creado: &lt;code&gt;PROJ-457 &quot;Optimize database connection pooling for peak load&quot;&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Martes: Bug de renderizado en frontend&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Usa el agente project-debugger para investigar: El gráfico del
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dashboard no se actualiza cuando llegan nuevos datos
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Informe guardado: &lt;code&gt;.claude&#x2F;reports&#x2F;debugging&#x2F;report-2026-01-07-1100.md&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;generate-jira-task
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Creado: &lt;code&gt;PROJ-458 &quot;Fix React state synchronization in DashboardChart component&quot;&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Miércoles: Caso edge de autenticación&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Usa el agente project-debugger para investigar: Los usuarios están
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;siendo deslogueados aleatoriamente después de cambios de contraseña
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Informe guardado: &lt;code&gt;.claude&#x2F;reports&#x2F;debugging&#x2F;report-2026-01-08-1400.md&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;generate-jira-task
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Creado: &lt;code&gt;PROJ-459 &quot;Handle session invalidation on password change correctly&quot;&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Cada investigación es independiente. El debugger crea informes con timestamp, y &lt;code&gt;&#x2F;generate-jira-task&lt;&#x2F;code&gt; siempre toma el más reciente. Tu historial de depuración se acumula en &lt;code&gt;.claude&#x2F;reports&#x2F;debugging&#x2F;&lt;&#x2F;code&gt;, dándote un archivo buscable de investigaciones pasadas.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;el-flujo-de-trabajo-completo&quot;&gt;El Flujo de Trabajo Completo&lt;&#x2F;h2&gt;




&lt;div class=&quot;workflow-container&quot; id=&quot;workflow&quot;&gt;
    &lt;canvas class=&quot;workflow-canvas&quot; aria-label=&quot;Workflow visualization&quot;&gt;&lt;&#x2F;canvas&gt;
&lt;&#x2F;div&gt;

&lt;script&gt;
(function() {
    const containerId = &#x27;workflow&#x27;;

    &#x2F;&#x2F; Decode HTML entities (Tera encodes &#x2F; as &amp;#x2F;)
    function decodeHTML(str) {
        const textarea = document.createElement(&#x27;textarea&#x27;);
        textarea.innerHTML = str;
        return textarea.value;
    }

    const stepsData = [
        
        
        { title: decodeHTML(&#x27;&amp;#x2F;generate-agent-team&#x27;), desc: decodeHTML(&#x27;Crea agentes especialistas&#x27;) },
        
        
        { title: decodeHTML(&#x27;Usa agentes diariamente&#x27;), desc: decodeHTML(&#x27;fastapi-expert react-specialist&#x27;) },
        
        
        { title: decodeHTML(&#x27;&amp;#x2F;generate-debugger&#x27;), desc: decodeHTML(&#x27;Crea project-debugger&#x27;) },
        
        
        { title: decodeHTML(&#x27;Depura issues&#x27;), desc: decodeHTML(&#x27;Guarda en .claude&amp;#x2F;reports&amp;#x2F;&#x27;) },
        
        
        { title: decodeHTML(&#x27;&amp;#x2F;generate-jira-task&#x27;), desc: decodeHTML(&#x27;Crea ticket de Jira&#x27;) }
        
    ];

    function initWorkflow() {
        const container = document.getElementById(containerId);
        if (!container) return;

        const canvas = container.querySelector(&#x27;.workflow-canvas&#x27;);
        const ctx = canvas.getContext(&#x27;2d&#x27;);

        let particles = [];
        let time = 0;

        const colors = {
            primary: &#x27;#00d4ff&#x27;,
            secondary: &#x27;#8b5cf6&#x27;,
            accent: &#x27;#00ff88&#x27;,
            particle: &#x27;#00ff88&#x27;,
            connection: &#x27;rgba(0, 212, 255, 0.4)&#x27;,
            text: &#x27;#e0e0e4&#x27;,
            subtext: &#x27;#8888a0&#x27;
        };

        function resize() {
            const rect = container.getBoundingClientRect();
            canvas.width = rect.width;
            canvas.height = Math.max(550, stepsData.length * 130 + 100);
            container.style.height = canvas.height + &#x27;px&#x27;;
        }
        resize();
        window.addEventListener(&#x27;resize&#x27;, resize);

        function getStepPositions() {
            const centerX = canvas.width &#x2F; 2;
            const startY = 70;
            const stepHeight = 120;

            return stepsData.map((step, i) =&gt; ({
                ...step,
                x: centerX,
                y: startY + i * stepHeight,
                width: Math.min(450, canvas.width * 0.85),
                height: 90,
                color: i % 2 === 0 ? colors.primary : colors.secondary
            }));
        }

        function createParticle(from, to) {
            return {
                fromX: from.x,
                fromY: from.y + from.height &#x2F; 2,
                toX: to.x,
                toY: to.y - to.height &#x2F; 2,
                progress: Math.random(),
                speed: 0.008 + Math.random() * 0.004
            };
        }

        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            const positions = getStepPositions();

            &#x2F;&#x2F; Draw connections
            ctx.strokeStyle = colors.connection;
            ctx.lineWidth = 3;
            for (let i = 0; i &lt; positions.length - 1; i++) {
                const from = positions[i];
                const to = positions[i + 1];

                ctx.beginPath();
                ctx.moveTo(from.x, from.y + from.height &#x2F; 2);
                ctx.lineTo(to.x, to.y - to.height &#x2F; 2);
                ctx.stroke();

                &#x2F;&#x2F; Arrow
                const midY = (from.y + from.height &#x2F; 2 + to.y - to.height &#x2F; 2) &#x2F; 2;
                ctx.fillStyle = colors.connection;
                ctx.beginPath();
                ctx.moveTo(from.x - 6, midY - 4);
                ctx.lineTo(from.x, midY + 6);
                ctx.lineTo(from.x + 6, midY - 4);
                ctx.closePath();
                ctx.fill();
            }

            &#x2F;&#x2F; Draw step boxes
            positions.forEach((pos, i) =&gt; {
                const x = pos.x - pos.width &#x2F; 2;
                const y = pos.y - pos.height &#x2F; 2;

                &#x2F;&#x2F; Glow
                ctx.shadowColor = pos.color;
                ctx.shadowBlur = 20;

                &#x2F;&#x2F; Box with rounded corners
                ctx.fillStyle = pos.color;
                ctx.beginPath();
                const radius = 8;
                ctx.moveTo(x + radius, y);
                ctx.lineTo(x + pos.width - radius, y);
                ctx.quadraticCurveTo(x + pos.width, y, x + pos.width, y + radius);
                ctx.lineTo(x + pos.width, y + pos.height - radius);
                ctx.quadraticCurveTo(x + pos.width, y + pos.height, x + pos.width - radius, y + pos.height);
                ctx.lineTo(x + radius, y + pos.height);
                ctx.quadraticCurveTo(x, y + pos.height, x, y + pos.height - radius);
                ctx.lineTo(x, y + radius);
                ctx.quadraticCurveTo(x, y, x + radius, y);
                ctx.closePath();
                ctx.fill();

                ctx.shadowBlur = 0;

                &#x2F;&#x2F; Border
                ctx.strokeStyle = colors.accent;
                ctx.lineWidth = 2;
                ctx.stroke();

                &#x2F;&#x2F; Step number
                ctx.fillStyle = &#x27;#0a0a0f&#x27;;
                ctx.font = &#x27;bold 18px JetBrains Mono, monospace&#x27;;
                ctx.textAlign = &#x27;left&#x27;;
                ctx.textBaseline = &#x27;middle&#x27;;
                ctx.fillText((i + 1) + &#x27;.&#x27;, x + 16, pos.y);

                &#x2F;&#x2F; Title
                ctx.fillStyle = &#x27;#0a0a0f&#x27;;
                ctx.font = &#x27;bold 16px JetBrains Mono, monospace&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.fillText(pos.title, pos.x + 12, pos.y - 10);

                &#x2F;&#x2F; Description (if exists)
                if (pos.desc) {
                    ctx.fillStyle = &#x27;rgba(10, 10, 15, 0.8)&#x27;;
                    ctx.font = &#x27;14px JetBrains Mono, monospace&#x27;;
                    ctx.fillText(pos.desc, pos.x + 12, pos.y + 16);
                }
            });

            &#x2F;&#x2F; Update and draw particles
            particles.forEach(p =&gt; {
                p.progress += p.speed;
                if (p.progress &gt;= 1) {
                    p.progress = 0;
                }

                const ease = p.progress * p.progress * (3 - 2 * p.progress);
                const x = p.fromX + (p.toX - p.fromX) * ease;
                const y = p.fromY + (p.toY - p.fromY) * ease;

                ctx.fillStyle = colors.particle;
                ctx.shadowColor = colors.particle;
                ctx.shadowBlur = 12;
                ctx.beginPath();
                ctx.arc(x, y, 4, 0, Math.PI * 2);
                ctx.fill();
                ctx.shadowBlur = 0;
            });

            time++;
            requestAnimationFrame(draw);
        }

        &#x2F;&#x2F; Initialize particles
        const positions = getStepPositions();
        for (let i = 0; i &lt; positions.length - 1; i++) {
            const p = createParticle(positions[i], positions[i + 1]);
            p.progress = i * 0.3;
            particles.push(p);
        }

        if (!window.matchMedia(&#x27;(prefers-reduced-motion: reduce)&#x27;).matches) {
            draw();
        } else {
            &#x2F;&#x2F; Static version
            const positions = getStepPositions();
            positions.forEach((pos, i) =&gt; {
                const x = pos.x - pos.width &#x2F; 2;
                const y = pos.y - pos.height &#x2F; 2;

                ctx.fillStyle = pos.color;
                ctx.beginPath();
                ctx.roundRect(x, y, pos.width, pos.height, 8);
                ctx.fill();

                ctx.fillStyle = &#x27;#0a0a0f&#x27;;
                ctx.font = &#x27;bold 16px JetBrains Mono&#x27;;
                ctx.textAlign = &#x27;center&#x27;;
                ctx.fillText(pos.title, pos.x, pos.y);
            });
        }
    }

    if (document.readyState === &#x27;loading&#x27;) {
        document.addEventListener(&#x27;DOMContentLoaded&#x27;, initWorkflow);
    } else {
        initWorkflow();
    }
})();
&lt;&#x2F;script&gt;

&lt;style&gt;
.workflow-container {
    background: var(--bg-0);
    border: 1px solid var(--divider-color);
    border-radius: 12px;
    padding: 1rem;
    margin: 1.5rem 0;
    position: relative;
    min-height: 550px;
}

.workflow-canvas {
    width: 100%;
    display: block;
}

@media (max-width: 768px) {
    .workflow-container {
        padding: 0.5rem;
    }
}
&lt;&#x2F;style&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;inicio-rapido&quot;&gt;Inicio Rápido&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;instalacion&quot;&gt;Instalación&lt;&#x2F;h3&gt;
&lt;p&gt;Instala directamente desde el marketplace de GitHub—no requiere clonar:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Añade el marketplace (configuración única)&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&#x2F;plugin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; marketplace add Cpicon&#x2F;claude-code-plugins&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Instala el plugin&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&#x2F;plugin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; install agent-team-creator&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Eso es todo. El plugin está listo para usar inmediatamente.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;primeros-comandos&quot;&gt;Primeros Comandos&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;Navega a tu proyecto&lt;&#x2F;li&gt;
&lt;li&gt;Ejecuta &lt;code&gt;&#x2F;generate-agent-team&lt;&#x2F;code&gt; para crear tus agentes especialistas&lt;&#x2F;li&gt;
&lt;li&gt;Comienza a usar tus especialistas: &lt;code&gt;Usa el agente [nombre-agente] para...&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Ejecuta &lt;code&gt;&#x2F;generate-debugger&lt;&#x2F;code&gt; para crear tu project debugger&lt;&#x2F;li&gt;
&lt;li&gt;Usa el debugger para investigar bugs: &lt;code&gt;Usa el agente project-debugger para investigar...&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Ejecuta &lt;code&gt;&#x2F;generate-jira-task&lt;&#x2F;code&gt; para convertir el informe de depuración en un ticket&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;lo-que-obtienes&quot;&gt;Lo Que Obtienes&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Comando&lt;&#x2F;th&gt;&lt;th&gt;Salida&lt;&#x2F;th&gt;&lt;th&gt;Valor&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;generate-agent-team&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;3-6 agentes especialistas&lt;&#x2F;td&gt;&lt;td&gt;Ayuda consciente del proyecto para features, preguntas, depuración&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;generate-debugger&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Agente orquestador&lt;&#x2F;td&gt;&lt;td&gt;Coordina especialistas para investigaciones complejas&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;generate-jira-task&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Ticket Jira o markdown&lt;&#x2F;td&gt;&lt;td&gt;Auto-encuentra último informe, crea ticket accionable&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;ahorro-de-tiempo&quot;&gt;Ahorro de Tiempo&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Tarea&lt;&#x2F;th&gt;&lt;th&gt;Antes&lt;&#x2F;th&gt;&lt;th&gt;Después&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Obtener ayuda consciente del proyecto&lt;&#x2F;td&gt;&lt;td&gt;N&#x2F;A (solo genérico)&lt;&#x2F;td&gt;&lt;td&gt;Inmediato&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Depurar issues complejos&lt;&#x2F;td&gt;&lt;td&gt;Horas de investigación&lt;&#x2F;td&gt;&lt;td&gt;Informes estructurados&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Escribir tickets de Jira&lt;&#x2F;td&gt;&lt;td&gt;15-30 min&lt;&#x2F;td&gt;&lt;td&gt;2-5 min&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;pruebalo-tu-mismo&quot;&gt;Pruébalo Tú Mismo&lt;&#x2F;h2&gt;
&lt;p&gt;El plugin es open source y está disponible en GitHub: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Cpicon&#x2F;claude-code-plugins&quot;&gt;Cpicon&#x2F;claude-code-plugins&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Instálalo con dos comandos, ejecuta &lt;code&gt;&#x2F;generate-agent-team&lt;&#x2F;code&gt;, y observa qué especialistas emergen para tu proyecto.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;contribuir-y-feedback&quot;&gt;Contribuir y Feedback&lt;&#x2F;h3&gt;
&lt;p&gt;¿Tienes ideas para mejoras? ¿Encontraste un bug? La pestaña &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Cpicon&#x2F;claude-code-plugins&#x2F;issues&quot;&gt;GitHub Issues&lt;&#x2F;a&gt; es donde puedes:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Solicitar features&lt;&#x2F;strong&gt; — Sugerir nuevas capacidades o mejoras&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Reportar bugs&lt;&#x2F;strong&gt; — Ayudar a mejorar la fiabilidad reportando issues que encuentres&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Discutir mejoras&lt;&#x2F;strong&gt; — Compartir ideas para mantenimiento y desarrollo del plugin&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Tu feedback da forma al roadmap del plugin.&lt;&#x2F;p&gt;
&lt;p&gt;En la &lt;a href=&quot;&#x2F;posts&#x2F;claude-code-plugin-journey-part1&#x2F;&quot;&gt;Parte 1&lt;&#x2F;a&gt;, te mostraré cómo construí este plugin—los bugs que encontré, los patrones que descubrí, y por qué la arquitectura funciona como lo hace.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Navegación de la Serie:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Parte 0&lt;&#x2F;strong&gt; (Estás aquí): Qué hace el plugin y cómo usarlo&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Parte 1&lt;&#x2F;strong&gt;: &lt;a href=&quot;&#x2F;posts&#x2F;claude-code-plugin-journey-part1&#x2F;&quot;&gt;El Patrón de Arquitectura Híbrida&lt;&#x2F;a&gt; — Construyendo el plugin&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Parte 2&lt;&#x2F;strong&gt;: &lt;a href=&quot;&#x2F;posts&#x2F;claude-code-plugin-journey-part2&#x2F;&quot;&gt;La Paradoja de la Herencia&lt;&#x2F;a&gt; — Insights de investigación&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">Claude Code Plugin Journey Parte 0: Agent Team Creator
¿Qué pasaría si pudieras apuntar una IA a tu proyecto y hacer que genere especialistas que realmente entienden tu stack? No asistentes genéricos—agentes que conocen tu arquitectura, tus patrones, tus convenciones.
Eso es lo que hace agent-team-creator. Déjame mostrarte el flujo de trabajo.
…</summary>
        </entry><entry xml:lang="es">
        <title>Patrones de Diseño en ML</title>
        <published>2023-03-04T00:00:00+00:00</published>
        <updated>2023-03-04T00:00:00+00:00</updated>
        <author>
            <name>Christian Picon Calderon</name>
        </author>
        <link rel="alternate" href="https://futurewithml.netlify.app/es/posts/chapter01-ml-pattern-design/" type="text/html"/>
        <id>https://futurewithml.netlify.app/es/posts/chapter01-ml-pattern-design/</id>
        
            <content type="html">&lt;h1 id=&quot;patrones-de-machine-learning&quot;&gt;&lt;strong&gt;Patrones de Machine Learning&lt;&#x2F;strong&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;¡Hola! En primer lugar, me embarco en un viaje para destacar los principales aspectos presentados en el libro “&lt;a href=&quot;https:&#x2F;&#x2F;www.oreilly.com&#x2F;library&#x2F;view&#x2F;machine-learning-design&#x2F;9781098115777&#x2F;&quot;&gt;Machine Learning Design Patterns&lt;&#x2F;a&gt;”. Esta serie está dirigida a ingenieros de machine learning, ingenieros de datos y científicos de datos. Omitiré la explicación de la terminología básica y me centraré en los matices de enfrentar los desafíos más comunes al desplegar modelos de machine learning. El concepto de patrones fue introducido en el campo de la ingeniería civil&#x2F;arquitectura por Christopher Alexander y cinco coautores en el libro titulado “A Pattern Language” (1977). La idea principal es que en una situación que ocurre recurrentemente, el patrón describe la solución central para este contexto y puede aplicarse varias veces para este u otros similares. Aquí, exploraremos los patrones más generales que pueden aplicarse al diseño de sistemas de machine learning.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Sin embargo, no podemos proceder sin definir los desafíos más comunes en ML:&lt;&#x2F;p&gt;
&lt;h2 id=&quot;calidad-de-datos&quot;&gt;&lt;strong&gt;Calidad de Datos&lt;&#x2F;strong&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Como ya sabrás, en ML aplica “Basura entra, basura sale”, debemos verificar la precisión, completitud, consistencia y oportunidad de los datos.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Precisión de datos&lt;&#x2F;strong&gt; se refiere al gran y arduo trabajo que realizan los ingenieros de datos. Estos ingenieros juegan un papel esencial en verificar y manejar errores tipográficos, entradas duplicadas, inconsistencias de medición, características faltantes y las particularidades de datos no estructurados. Por ejemplo, los duplicados pueden llevar al modelo a asignar más peso a esas muestras duplicadas durante el aprendizaje. Además, ejemplos de entrenamiento etiquetados incorrectamente introducen sesgo en el modelo.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Completitud de Datos&lt;&#x2F;strong&gt; asegura que tus datos de entrenamiento contengan una representación variada de cada etiqueta. Tiene el mismo efecto en el aprendizaje que los ejemplos duplicados en los datos de entrenamiento. Para lidiar con problemas de precisión y completitud de datos, deberías realizar un Análisis Exploratorio de Datos (EDA). Te animo a echar un vistazo a Pandas profile o Dtale para facilitar este análisis.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Consistencia de datos&lt;&#x2F;strong&gt; es otro aspecto común del machine learning. Como sabes, en el aprendizaje supervisado, necesitas datos etiquetados, así que aquí, deberíamos solicitar datos etiquetados o comenzar a etiquetarlos. El problema surge cuando los etiquetadores introducen sesgo, especialmente si los datos requieren conocimiento del dominio (como en imágenes médicas). Una técnica común es dividir el trabajo entre un grupo de personas, luego tener múltiples personas etiquetando cada ejemplo y tomar la etiqueta más comúnmente aplicada (veremos esto en profundidad en el patrón de diseño Fairness Lens). Las características inconsistentes también se consideran en esta sección ya que pueden cambiar con el tiempo (piensa en sensores con diferentes offset de calibración).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Oportunidad&lt;&#x2F;strong&gt; en datos se refiere a la latencia entre la ocurrencia del evento y la adición a la base de datos. Es más importante en aplicaciones de machine learning en tiempo real, así que en este caso, deberías registrar tantos datos como sea posible. Por ejemplo, agregar una marca de tiempo cuando se generó un punto de datos y cuando se agregó al almacenamiento.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;reproducibilidad&quot;&gt;&lt;strong&gt;Reproducibilidad&lt;&#x2F;strong&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;El machine learning, a diferencia del software tradicional, tiene un elemento inherente de aleatoriedad. Por ejemplo, los pesos de las matrices se inicializan con valores aleatorios, por lo que el modelo converge a diferentes salidas para diferentes ejecuciones de entrenamiento. Esto puede dificultar ejecutar comparaciones entre experimentos. Fijar un valor para seed puede resolver este problema.&lt;&#x2F;p&gt;
&lt;p&gt;Entrenar un modelo de ML involucra varios artefactos que necesitan fijarse para asegurar la reproducibilidad: los datos utilizados, el mecanismo de división usado para generar conjuntos de datos para entrenamiento y validación, preparación de datos e hiperparámetros del modelo, y variables como tamaño de lote y programación de tasa de aprendizaje. También aplica a las dependencias del framework de ML. Ejecutar cargas de trabajo de ML en contenedores y estandarizar versiones de bibliotecas puede ayudar a asegurar la repetibilidad.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;deriva-de-datos&quot;&gt;&lt;strong&gt;Deriva de Datos&lt;&#x2F;strong&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;La deriva de datos es un concepto importante en ML, especialmente en producción. La deriva de datos se refiere al desafío de asegurar que tus modelos de machine learning permanezcan relevantes. Para resolver la deriva, es esencial actualizar continuamente tu conjunto de datos de entrenamiento, reentrenar tu modelo y modificar el peso que tu modelo asigna a grupos particulares de datos de entrada. El análisis exploratorio de datos es una técnica requerida aquí para entender el comportamiento de los datos. Por ejemplo, predecir la probabilidad de una tormenta requiere explorar los datos disponibles de los sensores para este escenario. En la siguiente imagen, podemos ver que entrenar un modelo con datos anteriores al 2000 llevaría a predicciones inexactas.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;futurewithml.netlify.app&#x2F;es&#x2F;posts&#x2F;chapter01-ml-pattern-design&#x2F;chap1_datadrift.png&quot; alt=&quot;chap1_datadrift.png&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Copyright 2020 Google Inc. Licenciado bajo la Licencia Apache, Versión 2.0 (la “Licencia”); no puedes usar este archivo excepto en cumplimiento con la Licencia. Puedes obtener una copia de la Licencia en &lt;a href=&quot;http:&#x2F;&#x2F;www.apache.org&#x2F;licenses&#x2F;LICENSE-2.0&quot;&gt;http:&#x2F;&#x2F;www.apache.org&#x2F;licenses&#x2F;LICENSE-2.0&lt;&#x2F;a&gt; A menos que lo requiera la ley aplicable o se acuerde por escrito, el software distribuido bajo la Licencia se distribuye “TAL CUAL”, SIN GARANTÍAS O CONDICIONES DE NINGÚN TIPO, ya sean expresas o implícitas. Consulta la Licencia para el idioma específico que rige los permisos y limitaciones bajo la Licencia.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;escala&quot;&gt;&lt;strong&gt;Escala&lt;&#x2F;strong&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Encontrarás desafíos de escalado en diferentes fases de tu aplicación de ML, como recolección y preprocesamiento de datos, entrenamiento y servicio. El tamaño de tus datos dictará las herramientas requeridas para tu solución. Los ingenieros de ML son responsables de determinar la infraestructura necesaria para un trabajo de entrenamiento específico. Si tu conjunto de datos es lo suficientemente grande, el entrenamiento del modelo puede ser costoso en tiempo y computacionalmente. En el contexto del servicio de modelos, la infraestructura requerida para soportar un equipo de científicos de datos obteniendo predicciones es completamente diferente de la infraestructura necesaria para soportar un modelo en producción para millones de predicciones por hora. Veremos resiliencia y reproducibilidad en los capítulos 6 y 7.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;multiples-objetivos-el-gran-desafio-oculto&quot;&gt;&lt;strong&gt;Múltiples Objetivos&lt;&#x2F;strong&gt; (El gran desafío oculto)&lt;&#x2F;h2&gt;
&lt;p&gt;Los modelos en producción introducen un gran desafío para un ingeniero de ML porque el modelo está siendo usado por diferentes equipos&#x2F;roles en la organización. Teniendo este escenario, veremos que definir un modelo exitoso no es fácil. Cada usuario&#x2F;equipo&#x2F;rol tiene su propia definición de un modelo exitoso dadas sus necesidades. Por ejemplo, un científico de datos&#x2F;investigador de ML está interesado en minimizar la función de pérdida del modelo. El gerente de proyecto está interesado en generar valor vinculando este modelo a los productos de la organización, así que aquí empezamos a lidiar con cómo definir un KPI que imite el comportamiento de la función de pérdida. Finalmente, el equipo ejecutivo está interesado en aumentar los ingresos usando este modelo pero entienden el KPI más que una función matemática como la función de pérdida. Como viste, es responsabilidad del científico de datos trabajar junto con el gerente de proyecto para definir este KPI, luego llevarlo al equipo ejecutivo.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gracias&quot;&gt;Gracias&lt;&#x2F;h2&gt;
&lt;p&gt;Querido &lt;a href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;jameshclrk&#x2F;&quot;&gt;James Clark&lt;&#x2F;a&gt;, solo quería tomarme un momento para agradecerte por inspirarme&#x2F;ayudarme a comenzar mi propio blog personal. Tu blog, https:&#x2F;&#x2F;jamesclark.dev&#x2F;, ha sido una fuente de inspiración para mí, y tu disposición a compartir tus experiencias y conocimientos ha sido invaluable. Gracias a tu guía, ahora tengo una plataforma para expresar mis pensamientos, compartir mis ideas y conectar con otros que comparten mis pasiones. Tu apoyo y aliento han sido instrumentales para ayudarme a comenzar, y estoy verdaderamente agradecido por todo lo que has hecho por mí. ¡Gracias de nuevo por todo, James!&lt;&#x2F;p&gt;
</content>
        <summary type="html">Patrones de Machine Learning
¡Hola! En primer lugar, me embarco en un viaje para destacar los principales aspectos presentados en el libro “Machine Learning Design Patterns”. Esta serie está dirigida a ingenieros de machine learning, ingenieros de datos y científicos de datos. Omitiré la explicación de la terminología básica y me centraré en los matices de enfrentar los desafíos más comunes al desplegar modelos de machine learning. El concepto de patrones fue introducido en el campo de la ingeniería civil/arquitectura por Christopher Alexander y cinco coautores en el libro titulado “A Pattern Language” (1977). La idea principal es que en una situación que ocurre recurrentemente, el patrón describe la solución central para este contexto y puede aplicarse varias veces para este u otros similares. Aquí, exploraremos los patrones más generales que pueden aplicarse al diseño de sistemas de machine learning.
…</summary>
        </entry>
</feed>
