<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
  <title>Bitácora de Gioser</title>
  <link>https://gioser.net/blog/</link>
  <atom:link href="https://gioser.net/blog/feed.xml" rel="self" type="application/rss+xml"/>
  <description>Lo que se construye en el taller, contado con los números a la vista.</description>
  <language>es</language>
  <lastBuildDate>Sat, 24 Oct 2026 09:00:00 -0500</lastBuildDate>
  <item>
    <title>Tu WordPress, sin WordPress: el mismo sitio al píxel, con su tienda, sin una sola línea de PHP</title>
    <link>https://gioser.net/blog/tu-wordpress-sin-wordpress/</link>
    <guid isPermaLink="true">https://gioser.net/blog/tu-wordpress-sin-wordpress/</guid>
    <pubDate>Sat, 24 Oct 2026 09:00:00 -0500</pubDate>
    <dc:creator>Redacción Gioser</dc:creator>
    <category>tawasuyu · Hacer</category>
    <description>qhatu absorbe un sitio WordPress en un comando y lo deja igual al píxel, sin PHP, sin base de datos y sin plugins, y si vende con WooCommerce se trae también la tienda: en el sitio real de un cliente, 9 de 9 programas de WordPress contestaban a cualquiera y en la copia no contesta ninguno; armar cada página pasó de unos 825 a unos 135 milisegundos; ninguna dirección vieja se pierde; y se sigue editando en el lugar, con historia firmada y vuelta atrás.</description>
    <enclosure url="https://gioser.net/blog/medios/qhatu-wordpress-portada.jpg" type="image/jpeg" length="86164"/>
    <content:encoded><![CDATA[<p class="lede">Cada vez que alguien abre una página de un sitio WordPress, en el servidor arranca un programa: lee la base de datos, carga el tema, despierta cada plugin, arma el HTML y lo manda. Lo mismo, una y otra vez, para un texto que cambia una vez por mes. Y mientras tanto, ese programa deja abiertas a todo internet las puertas por donde se administra. Este artículo cuenta cómo <strong>qhatu</strong> —el gestor de contenidos de tawasuyu— se lleva un sitio WordPress real entero, lo deja <strong>igual al píxel</strong>, se trae también su tienda de WooCommerce, y le quita todo lo que se podía atacar.</p>

<figure class="foto">
  <img src="https://gioser.net/blog/medios/qhatu-wordpress-portada.jpg" alt="Gráfico: a la izquierda, WordPress con 9 de 9 programas que contestan a cualquiera, con la lista de sus direcciones —wp-login.php, wp-admin, xmlrpc.php, wp-json, el listado de usuarios, author=1, readme.html, install.php, wp-cron.php—; a la derecha, qhatu y saywa con 0 de 9, 0 píxeles distintos de 3.278.400, 825 a 135 milisegundos y cero PHP" width="1600" height="900" loading="eager">
  <figcaption>Medido el 24 de octubre de 2026 sobre el sitio real de un cliente y su copia.</figcaption>
</figure>

<h2>El sitio que se arma en cada visita</h2>

<p>WordPress es la forma más común de tener un sitio, y hay buenas razones: se instala en una tarde, hay un tema para todo, y un constructor como Elementor deja diseñar sin escribir código. El precio se paga después, y en cuotas. Cada plugin es código ajeno que corre con <em>todos</em> los permisos del sitio; cada actualización que se posterga es una puerta; y la base de datos, el login y la API quedan escuchando las veinticuatro horas, aunque el sitio lo edite una persona dos veces por mes.</p>

<p>El sitio con el que se probó todo esto es el de un cliente real: un centro de retiros hecho con WordPress, el tema WoodMart y Elementor Pro, con 64 páginas, una galería, un blog y dos formularios de contacto. Un sitio común, del tipo que hay a millones. El pedido fue simple: <strong>que quede igualito, y que se pueda seguir editando fácil</strong>.</p>

<h2>Un comando</h2>

<p>Lo que el primer día se hizo a mano —bajar el sitio renderizado, limpiar lo que WordPress agrega a cada nombre de archivo, reapuntar los formularios— hoy es un verbo:</p>

<pre><code>qhatu absorb https://el-sitio.com/ carpeta</code></pre>

<p>Lee los mapas del sitio que publica WordPress, baja cada página y todo lo que necesita —hojas de estilo, scripts, imágenes en todos sus tamaños, fuentes, íconos—, y deja cada referencia apuntando a la copia local. No baja lo que no es contenido: el carrito, el panel de administración, los feeds, las búsquedas. Si una parte del sitio la arma JavaScript recién en el navegador, con <code>--render</code> cada página pasa antes por un Chrome sin pantalla y se guarda ya armada. Sobre el sitio del cliente:</p>

<div class="tabla" role="region" aria-label="La absorción del sitio real" tabindex="0">
<table>
  <thead><tr><th scope="col">qué</th><th scope="col">medido</th></tr></thead>
  <tbody>
    <tr><td>páginas</td><td class="propio">64</td></tr>
    <tr><td>recursos (hojas, scripts, imágenes, fuentes)</td><td class="propio">448, 45 MB</td></tr>
    <tr><td>tiempo, con una pausa de cortesía entre pedido y pedido</td><td class="propio">6 minutos</td></tr>
    <tr><td>referencias rotas en la copia</td><td class="propio">0</td></tr>
  </tbody>
</table>
</div>

<p>Y no hace falta que sea WordPress: el mismo verbo se llevó un Joomla, una demo de Squarespace que arma todo con JavaScript y el primer sitio web de la historia, el de CERN, con cero referencias rotas en los tres.</p>

<h2>Igual al píxel, y con brazo de control</h2>

<p>«Igualito» se puede medir. Se abrió la misma página del original y de la copia en Chrome, a 1366 por 2400 píxeles, y se compararon las dos capturas punto por punto. En la portada y en una entrada del blog, <strong>0 píxeles distintos de 3.278.400</strong>. Para que ese cero signifique algo, la prueba lleva brazo de control: cada captura tiene 216.987 colores distintos, así que no se están comparando dos páginas en blanco.</p>

<p>Y la honestidad incluye lo que no dio cero. En una tercera página aparecieron 1.785 píxeles distintos en la franja del menú. Antes de culpar a la copia se comparó el original <em>consigo mismo</em>, dos veces: dio 1.642 y 0. Es la propia página, que no se pinta igual dos veces seguidas.</p>

<h2>Ningún enlace viejo se rompe</h2>

<p>Un sitio con años tiene enlaces con años: en Facebook, en correos, en otros blogs. WordPress contesta a direcciones que nadie escribió a mano —<code>/?p=123</code>, <code>/2023/05/una-entrada/</code>, las categorías, el feed— y una mudanza que las pierde deja un rastro de errores 404. qhatu arma una tabla con todas ellas y el servidor la consulta antes que los archivos. Contra el sitio en vivo: <strong>143 direcciones viejas, ninguna en 404</strong> —55 que siguen siendo una página y 88 que la tabla lleva a su lugar nuevo—. Y una inventada sigue dando 404, que es lo que tiene que pasar.</p>

<h2>Nada que hackear</h2>

<p>Un escáner de WordPress empieza siempre igual: pregunta por las direcciones que todo WordPress tiene. Se hizo esa misma pregunta a los dos sitios, en modo pasivo —sólo pedidos de lectura a direcciones públicas, sin probar una sola contraseña—:</p>

<div class="tabla" role="region" aria-label="Lo que contesta cada sitio" tabindex="0">
<table>
  <thead><tr><th scope="col">dirección</th><th scope="col">qué es</th><th scope="col">WordPress</th><th scope="col">copia</th></tr></thead>
  <tbody>
    <tr><td><code>/wp-login.php</code></td><td>la puerta del login</td><td>contesta</td><td class="propio">404</td></tr>
    <tr><td><code>/wp-admin/</code></td><td>el panel</td><td>contesta</td><td class="propio">404</td></tr>
    <tr><td><code>/xmlrpc.php</code></td><td>la puerta clásica de la fuerza bruta en lote</td><td>contesta</td><td class="propio">404</td></tr>
    <tr><td><code>/wp-json/</code></td><td>la API</td><td>contesta</td><td class="propio">404</td></tr>
    <tr><td><code>/wp-json/wp/v2/users</code></td><td>la lista de quienes pueden entrar</td><td>contesta, con 3 nombres</td><td class="propio">404</td></tr>
    <tr><td><code>/?author=1</code></td><td>el nombre de usuario del primer autor</td><td>lo dice</td><td class="propio">no</td></tr>
    <tr><td><code>/readme.html</code></td><td>la versión exacta</td><td>contesta</td><td class="propio">404</td></tr>
    <tr><td><code>/wp-admin/install.php</code></td><td>el instalador</td><td>contesta</td><td class="propio">404</td></tr>
    <tr><td><code>/wp-cron.php</code></td><td>tareas que dispara cualquiera</td><td>contesta</td><td class="propio">404</td></tr>
  </tbody>
</table>
</div>

<p><strong>Nueve de nueve contra cero de nueve.</strong> Además, el original anunciaba en su propio código la versión exacta de WordPress y de dos de sus plugins: exactamente lo que un atacante busca para cruzar con una lista de fallas conocidas. No es que la copia tenga esas puertas mejor cerradas: <strong>no las tiene</strong>. No hay PHP que ejecutar, ni base de datos que consultar, ni usuarios que adivinar.</p>

<p>Midiendo esto apareció un detalle que vale contar. La copia todavía decía «WordPress» en una etiqueta invisible del HTML, heredada del original: un escáner la leía y anunciaba un WordPress que ya no existía. El absorbedor ahora la saca.</p>

<p>¿Y los formularios de contacto, que en WordPress son un plugin más? En la copia los atiende una <strong>función WebAssembly</strong> que corre en el servidor con capacidades declaradas: puede guardar lo que llega, leer el reloj y mandar el aviso por correo, y nada más. No puede leer el disco; lo que no pidió no existe para ella. Los mensajes se leen en el panel, y bajan como planilla. La lupa de búsqueda que la copia puede sumar a su menú es otra función así: lee un índice que se publica junto con el sitio, y no hay servidor de búsqueda que atacar.</p>

<h2>Y si además vende</h2>

<p>Muchos WordPress son también una tienda, con WooCommerce. Una tienda no es un conjunto de páginas: es un catálogo con precios, variantes y existencias, y un cobro. Así que no se copia como HTML: con <code>--as-content</code>, qhatu lee el catálogo por la misma API pública que usa el carrito de WooCommerce y cada producto entra a la tienda propia de qhatu con su nombre, su precio exacto, su moneda, sus imágenes y una variante por cada combinación —talle, color—, con la que está agotada marcada como agotada. El precio nunca pasa por un número con coma: se guarda en centavos, y al comprar el servidor lo recalcula contra el catálogo publicado, así nadie paga lo que se le ocurra mandando otro número.</p>

<p>Se probó contra un WooCommerce de verdad, con los productos de ejemplo que trae el propio WooCommerce: <strong>16 productos y 7 variantes</strong> entraron, y un instrumento que compara la tienda original contra la copia, producto por producto y variante por variante, dio <strong>iguales</strong>. Su brazo de control: después de absorber se cambió un precio y se agotó una variante en el original, y el instrumento nombró exactamente esas dos diferencias. Las reseñas de cada producto vienen con él, al pie de su página. Y con una contraseña de aplicación de WordPress —la que el propio WordPress deja crear para estos casos— viene también cuántas unidades quedan de cada producto y de cada variante: el servidor descuenta lo que se vende. Después se compró: una sudadera, al carrito, a pagar con PayPal en su entorno de pruebas, y la tienda volvió diciendo que el pedido estaba pagado, con la captura de PayPal anotada del lado del servidor.</p>

<p>Esa tienda está en línea, para verla y comprar con plata de mentira: <a href="https://tienda.gioser.net/">tienda.gioser.net</a>.</p>

<p>Y no parecen dos sitios pegados. Lo que qhatu arma —los productos, la lista, el carrito, las entradas del blog— va adentro de la cabecera, el menú, el pie, los colores y las letras del sitio original. Medido: la cabecera de una página que vino del original y la de un producto armado por qhatu dan <strong>0 píxeles distintos</strong>. El menú del celular abre en la copia aunque el WordPress original ya esté apagado, y ya no ofrece «Finalizar compra» ni «Mi cuenta», que en la copia no existen.</p>

<h2>Más rápido, y medido sin trampa</h2>

<p>Cinco páginas, cinco cargas en frío de cada lado —un navegador nuevo por carga, sin caché—, alternando original y copia para que una mala racha de la red no caiga entera de un lado. Las medianas:</p>

<div class="tabla" role="region" aria-label="Velocidad medida, original contra copia" tabindex="0">
<table>
  <thead><tr><th scope="col">página</th><th scope="col">primer byte</th><th scope="col">lo más grande pintado</th><th scope="col">carga completa</th></tr></thead>
  <tbody>
    <tr><td>portada</td><td>2,5&nbsp;s&nbsp;→ <strong>0,9&nbsp;s</strong></td><td>6,1&nbsp;s&nbsp;→ <strong>4,9&nbsp;s</strong></td><td>9,9&nbsp;s&nbsp;→ <strong>5,9&nbsp;s</strong></td></tr>
    <tr><td>página de servicio</td><td>1,9&nbsp;s&nbsp;→ <strong>0,8&nbsp;s</strong></td><td>6,5&nbsp;s&nbsp;→ <strong>3,8&nbsp;s</strong></td><td>14,9&nbsp;s&nbsp;→ <strong>5,4&nbsp;s</strong></td></tr>
    <tr><td>página larga con galería</td><td>2,3&nbsp;s&nbsp;→ <strong>0,9&nbsp;s</strong></td><td>11,7&nbsp;s&nbsp;→ <strong>6,3&nbsp;s</strong></td><td>22,3&nbsp;s&nbsp;→ <strong>7,9&nbsp;s</strong></td></tr>
    <tr><td>listado del blog</td><td>2,4&nbsp;s&nbsp;→ <strong>0,7&nbsp;s</strong></td><td>4,5&nbsp;s&nbsp;→ <strong>4,1&nbsp;s</strong></td><td>5,1&nbsp;s&nbsp;→ 5,3&nbsp;s</td></tr>
    <tr><td>una entrada</td><td>2,3&nbsp;s&nbsp;→ <strong>0,8&nbsp;s</strong></td><td>5,9&nbsp;s&nbsp;→ <strong>2,5&nbsp;s</strong></td><td>7,0&nbsp;s&nbsp;→ <strong>5,2&nbsp;s</strong></td></tr>
  </tbody>
</table>
</div>

<p>Los bytes que viajan son prácticamente los mismos: es la misma página. Lo que cambia es el servidor. Y hay una salvedad que un artículo honesto tiene que hacer: los dos sitios están en servidores distintos, en lugares distintos, y la copia quedaba más cerca de donde se midió. Así que se separó la red del software. Abrir la conexión cuesta 392 milisegundos hasta el original y 179 hasta la copia; eso es distancia, no código. Descontando una ida y vuelta de cada lado, lo que queda es el trabajo de armar la página:</p>

<figure class="foto">
  <svg viewBox="0 0 640 132" width="100%" role="img" aria-label="Gráfico de barras: armar una página le cuesta unos 825 milisegundos a WordPress y unos 135 a saywa, cerca de seis veces menos.">
    <text x="0" y="22" style="font:500 14px var(--sans);fill:var(--tinta)">WordPress: ~825 ms por página</text>
    <rect x="0" y="32" width="610" height="22" rx="4" style="fill:var(--tinta-tenue)"></rect>
    <text x="0" y="90" style="font:500 14px var(--sans);fill:var(--tinta)">saywa: ~135 ms por página</text>
    <rect x="0" y="100" width="100" height="22" rx="4" style="fill:var(--acento)"></rect>
  </svg>
  <figcaption>El trabajo del servidor, con la distancia de red descontada. Medido con curl, cinco pedidos de cada lado.</figcaption>
</figure>

<p>Y en un teléfono hay algo más. Al publicar, qhatu prepara cada imagen grande en varios anchos y el navegador elige la que le sirve: en la portada del cliente, vista a 390 píxeles de ancho, se bajan <strong>72 % menos bytes de imagen</strong>, sin mover un píxel en una pantalla de escritorio.</p>

<h2>Y se sigue editando, en el lugar</h2>

<p>Una copia estática que no se puede tocar sería un museo. La de qhatu se edita desde un panel que vive en su propia dirección —nada del sitio público lo enlaza—, sobre la página misma, tal como se ve:</p>

<figure class="foto">
  <img src="https://gioser.net/blog/medios/qhatu-editor-y-resultado.jpg" alt="Captura de pantalla: a la izquierda, el panel de qhatu con un artículo abierto —fecha, imagen de portada y el cuerpo con su barra de negrita, cursiva, títulos, listas, citas, enlaces e imágenes, y el botón Guardar—; a la derecha, el mismo artículo publicado en la bitácora de gioser, con su ilustración y el título «Qué es tawasuyu»" width="1600" height="705" loading="lazy">
  <figcaption>El panel de qhatu y lo que publica, lado a lado: a la izquierda se escribe, a la derecha está el artículo tal como lo ve un lector. Es esta misma bitácora, que también arma qhatu.</figcaption>
</figure>

<ul>
  <li><strong>Clic en un texto y se escribe.</strong> Una barra ofrece negrita, cursiva, enlaces, listas, títulos y citas, y los colores son <em>los del sitio</em>, no un selector cualquiera. Pegar desde Word o Google Docs deja el formato y tira la basura.</li>
  <li><strong>Clic en una imagen y se reemplaza.</strong> Elegir varias de una vez agrega fotos a una galería: cada una de más duplica el ítem y le pone la suya.</li>
  <li><strong>Duplicar, mover y borrar</strong> cualquier bloque: una tarjeta, una sección, un ítem de una lista. Y una página nueva es la copia de otra, en la dirección que se quiera.</li>
  <li><strong>La paleta y las letras del sitio a un costado.</strong> Los colores que usa la página, contados; se cambia uno y se ve al instante, y un botón lo aplica a las ochenta y tantas hojas de estilo que dejó Elementor. Las tipografías se cambian igual. Si un texto deja de leerse sobre su fondo, el panel lo dice con la medida de contraste en la mano.</li>
  <li><strong>Publicar es un acto firmado.</strong> Guardar cambia la carpeta; publicar convierte el sitio en una versión nueva, firmada, que el servidor sirve entera o no sirve. La historia dice qué cambió entre dos versiones cualesquiera, página por página. Volver a la anterior es un botón, y deja también la carpeta como estaba.</li>
</ul>

<p>Y lo que el original armó con Elementor ya no queda como un HTML que sólo se toca en el lugar: con <code>--as-content</code> entra como bloques de qhatu —portadas, columnas, carruseles, preguntas frecuentes— que se editan con el editor de bloques y se pintan con el tema del sitio. En el del cliente, dos de sus páginas de Elementor entraron como <strong>22 y 12 bloques</strong>, cinco portadas con su foto de fondo y tres carruseles de diez a doce fotos, sin un solo widget que quedara sin equivalente y sin una imagen sin bajar.</p>

<p>Todo eso corre en <strong>saywa</strong>, el servidor web de tawasuyu. En la máquina donde vive este sitio, saywa y la forja propia del proyecto ya reemplazaron a cuatro programas: el servidor web, la forja de git, el proxy y el intérprete de PHP. Alguien escribió las dos piezas desde cero, en Rust, con una regla que se repite en todo el proyecto: lo que no se midió no se afirma.</p>

<aside class="ficha" aria-labelledby="ficha-qhatu">
  <h2 id="ficha-qhatu">Lo medimos</h2>
  <dl>
    <div><dt>Programas de WordPress que contestan, original / copia</dt><dd>9 / 0</dd></div>
    <div><dt>Píxeles distintos en la portada</dt><dd>0 de 3.278.400</dd></div>
    <div><dt>Páginas y recursos absorbidos</dt><dd>64 y 448</dd></div>
    <div><dt>Referencias rotas en la copia</dt><dd>0</dd></div>
    <div><dt>Direcciones viejas que siguen llegando</dt><dd>143 de 143</dd></div>
    <div><dt>Armar una página, WordPress / saywa</dt><dd>~825 / ~135 ms</dd></div>
    <div><dt>Bytes de imagen en un teléfono</dt><dd>−72 %</dd></div>
    <div><dt>Tienda WooCommerce de prueba, original contra copia</dt><dd>iguales (16 productos, 7 variantes)</dd></div>
    <div><dt>Cabecera de una página original / una de qhatu</dt><dd>0 píxeles distintos</dd></div>
    <div><dt>qhatu: piezas, líneas de Rust con sus tests, tests</dt><dd>8 · 23.517 · 185</dd></div>
    <div><dt>saywa: piezas, líneas de Rust con sus tests, tests</dt><dd>13 · 21.510 · 221</dd></div>
  </dl>
  <p>Mediciones del 24 de octubre de 2026, desde una laptop, sobre el sitio de un cliente y su copia; la tienda, las direcciones viejas, las imágenes y los bloques de Elementor, el 28 de octubre; conteos sobre el repositorio de tawasuyu el 28 de octubre.</p>
</aside>

<h2>Lo que todavía no</h2>

<ul>
  <li><strong>El cobro con plata de verdad no se probó.</strong> La tienda cobra con PayPal, y de punta a punta se probó en su entorno de pruebas; con una cuenta real, todavía no.</li>
  <li><strong>De WooCommerce se trae el catálogo y sus reseñas, no la historia.</strong> Los pedidos viejos, los clientes, los cupones y las reglas de envío e impuestos se quedan en el WordPress.</li>
  <li><strong>Renderizar es lento.</strong> Con <code>--render</code> el sitio del cliente tardó unos 30 minutos en lugar de 6: Chrome carga cada página entera.</li>
  <li><strong>Hay cuentas de lectores, páginas sólo para miembros y boletín, pero no membresía paga.</strong></li>
  <li><strong>Los números de velocidad son de un día y desde un lugar.</strong> Por eso va la separación de la red: es la parte que no depende de dónde se mida.</li>
</ul>

<h2>Cómo probarlo</h2>

<p>La tienda de este artículo está en <a href="https://tienda.gioser.net/">tienda.gioser.net</a>, y su panel está abierto: en <a href="https://tienda.gioser.net/_/">tienda.gioser.net/_/</a> cualquiera puede entrar con «Probar como autor» y editarla a gusto; lo suyo se borra a las 24 horas. El mismo qhatu arma esta bitácora y el <a href="https://manual.tawasuyu.net/">manual de tawasuyu</a>, y con una línea más en su configuración se vuelve una <a href="https://wiki.gioser.net/">wiki</a>: enlaces por título, la historia firmada de cada página, y dos personas que editan la misma página a la vez sin pisarse. Para tener lo mismo en una máquina propia, una VPS recién creada alcanza: <code>qhatu server install --domain el-sitio.com</code> deja el servidor, el panel y el certificado andando —medido sobre Debian 13 y Fedora 44, con una autoridad de certificados de prueba: la portada contesta por HTTPS a los siete segundos de tener acceso a la máquina— y <code>qhatu absorb</code> se trae el WordPress. qhatu vive en el repositorio de tawasuyu —<a href="https://git.tawasuyu.net/tawasuyu/tawasuyu">git.tawasuyu.net</a>, en un servidor propio— bajo <code>02_ruway/qhatu</code>, y saywa bajo <code>03_ukupacha/saywa</code>. Los instrumentos de este artículo —exposición, velocidad, píxeles y el careo de la tienda— están en <code>scripts/qhatu-careo/</code>: cualquiera puede correrlos contra su propio WordPress y contra su copia, y comparar.</p>]]></content:encoded>
  </item>
  <item>
    <title>Arje: el init que recuerda — el sistema entero como un commit firmado</title>
    <link>https://gioser.net/blog/arje-el-init-que-recuerda/</link>
    <guid isPermaLink="true">https://gioser.net/blog/arje-el-init-que-recuerda/</guid>
    <pubDate>Fri, 23 Oct 2026 09:00:00 -0500</pubDate>
    <dc:creator>Redacción Gioser</dc:creator>
    <category>tawasuyu · Raíz</category>
    <description>Arje, el init en Rust de tawasuyu que reemplaza a systemd: el arranque como grafo de capacidades tipadas, el sistema entero como un commit firmado —con log, diff, bisect, blame y autopsia—, jaulas que se derivan de la unidad en vez de configurarse, y la resurrección de una máquina completa por el cable, sin servidor en el medio.</description>
    <enclosure url="https://gioser.net/blog/medios/arje-portada.jpg" type="image/jpeg" length="452078"/>
    <content:encoded><![CDATA[<p class="lede">Apretás el botón de encendido. Antes de que exista tu escritorio, tus archivos o tu red, el núcleo del sistema lanza <strong>un solo programa</strong> y le entrega la máquina: el <em>init</em>, el proceso número 1. De él desciende todo lo que va a correr ese día, y si él muere, el sistema entero muere con él. En casi todos los Linux del mundo ese programa es <strong>systemd</strong>. En las máquinas de tawasuyu es <strong>arje</strong> —del griego <em>ἀρχή</em>: origen, principio—, y este artículo cuenta qué hace distinto, con los números a la vista.</p>

<figure class="foto">
  <img src="https://gioser.net/blog/medios/arje-portada.jpg" alt="Ilustración: una persona con poncho andino mira desde un risco un valle al amanecer; en el cielo brilla una chakana, al centro flota la cadena del arranque —UEFI, kernel, grafo, chakana, sesión— y a la derecha sube una columna de commits luminosos desde los servidores del valle" width="1600" height="900" loading="eager">
  <figcaption>Ilustración: el arranque como cadena de actos, y el sistema como una columna de commits que sube desde las máquinas del valle.</figcaption>
</figure>

<h2>El programa que corre antes que todos</h2>

<p>Un init hace, como mínimo, tres cosas: arranca los servicios en el orden correcto, adopta a los procesos huérfanos, y vuelve a levantar lo que se cae. Parece poco. No lo es: es el único proceso que no puede fallar nunca —si el proceso 1 muere, el núcleo entra en pánico y la pantalla se congela— y el único que ve nacer y morir a todos los demás. Quien escribe el init decide cómo arranca tu computadora, qué corre con qué permisos, y qué pasa cuando algo sale mal.</p>

<p>Por eso importa quién lo escribe. Y por eso conviene mirar quién lo escribe hoy.</p>

<h2>systemd: cómo el arranque consiguió dueño</h2>

<p>systemd nació en 2010 dentro de Red Hat para resolver problemas reales: los init de scripts de shell eran lentos, frágiles y no supervisaban nada. Hay que decirlo sin caricatura: <strong>ganó porque lo anterior era peor</strong>. Pero ganó de una forma particular: absorbiendo. Lo que empezó como un init hoy incluye el gestor de sesiones (logind), el de logs (journald, con formato binario propio), el de red (networkd), el de DNS (resolved), el de hora, el de usuarios (homed), el de particiones (repart), contenedores (nspawn), un cargador de arranque y una docena de piezas más. Ninguna distribución grande puede ya quitarle una pieza sin romper las demás: Debian lo adoptó tras una de las votaciones más ásperas de su historia, y GNOME directamente no arranca completo sin sus interfaces.</p>

<p>Eso es software corporativo en el sentido exacto del término: nació para resolverle los problemas a una empresa, creció absorbiendo lo que nadie le pidió absorber, y llegó a un punto donde <strong>bajarse ya no es una opción práctica</strong>. Su creador trabaja hoy en Microsoft; el proyecto lo gobierna el calendario de Red Hat/IBM. No hace falta teoría conspirativa alguna: alcanza con constatar que la pieza que decide cómo arranca casi todo Linux del planeta tiene un roadmap, y ese roadmap no lo escribís vos.</p>

<p>Y hay un argumento técnico, más frío que el político. El proceso 1 de systemd interpreta archivos de configuración con un parser de texto, habla D-Bus, y carga sobre sí una superficie enorme de código C. En el proyecto tawasuyu eso se resume en una doctrina de cuatro palabras: <em>«un parser en el init es una bomba»</em>. Todo lo que el proceso 1 hace de más es superficie de ataque en el único proceso que no puede morir.</p>

<figure class="foto">
  <svg viewBox="0 0 640 150" width="100%" role="img" aria-label="Gráfico de barras: el código C de systemd suma 1.175.757 líneas; arje completo mide 48.171 líneas de Rust, alrededor del 4 por ciento.">
    <text x="0" y="22" style="font:500 14px var(--sans);fill:var(--tinta)">systemd (C y cabeceras)</text>
    <rect x="0" y="32" width="610" height="22" rx="4" style="fill:var(--tinta-tenue)"/>
    <text x="604" y="48" text-anchor="end" style="font:500 13px var(--mono);fill:var(--fondo)">1.175.757 líneas</text>
    <text x="0" y="92" style="font:500 14px var(--sans);fill:var(--tinta)">arje (31 crates, Rust)</text>
    <rect x="0" y="102" width="25" height="22" rx="4" style="fill:var(--acento)"/>
    <text x="27" y="118" style="font:500 13px var(--mono);fill:var(--tinta)">48.171 líneas — el 4 %</text>
  </svg>
  <figcaption>Tamaño a la misma escala. arje: contado sobre el repositorio de tawasuyu el 22 de octubre de 2026 (31 crates, 504 tests). systemd: archivos .c y .h de su repositorio público el 23 de octubre de 2026 (commit 154df43); con datos de hardware, traducciones y documentación el repositorio entero suma 2,48 millones. Las dos barras cuentan igual: líneas físicas, con tests y comentarios. La barra chica no es modestia: es la tesis — lo que el proceso 1 no carga, no se le puede caer.</figcaption>
</figure>

<h2>Arje, en una frase</h2>

<p>Arje cubre desde «presionaste ENCENDER» hasta «el sistema está en pie»: un cargador de arranque UEFI propio, el proceso 1, la supervisión, el aislamiento y la compatibilidad con lo viejo. Y habla otro idioma, porque piensa distinto:</p>

<div class="tabla" role="region" aria-label="Vocabulario: qué dice systemd y qué dice arje" tabindex="0">
<table>
  <thead><tr><th scope="col">systemd dice</th><th scope="col">arje dice</th><th scope="col">la diferencia</th></tr></thead>
  <tbody>
    <tr><td>unit / service</td><td><span class="pieza">Ente</span>, descrito por una <span class="pieza">Card</span></td><td>la unidad no es un archivo <code>.ini</code>: es un objeto tipado, validado al compilar</td></tr>
    <tr><td>PID 1 (<code>systemd</code>)</td><td><span class="pieza">arje-zero</span>, «el Ente #0»</td><td>mínimo a propósito: nunca lógica de servicio en el proceso 1</td></tr>
    <tr><td>default target + symlinks de <code>enable</code></td><td>la <span class="pieza">Semilla</span></td><td>lo que arranca es un árbol declarado en un solo objeto, no una tabla de enlaces repartida por el disco</td></tr>
    <tr><td>el conjunto de units activas</td><td>el <span class="pieza">fractal</span></td><td>un grafo vivo de Entes, con eventos tipados</td></tr>
    <tr><td>D-Bus como plano de control</td><td><span class="pieza">arje-bus</span></td><td>socket propio; la identidad de quien pide la inyecta el núcleo y no se puede falsear</td></tr>
    <tr><td>sandbox por directivas</td><td>el <span class="pieza">soma</span> de la Card</td><td>namespaces, cgroups, límites y jaulas declarados en el mismo objeto que describe al proceso</td></tr>
  </tbody>
</table>
</div>

<h2>Cinco decisiones que lo cambian todo</h2>

<p><strong>1 — La unidad es un tipo, no un archivo de texto.</strong> Una Card es una estructura de Rust serializada: no hay parser de sintaxis en el proceso 1, hay validación en compilación. Un campo mal escrito no es un warning en un log que nadie lee: es un error antes de que exista el binario.</p>

<p><strong>2 — Las dependencias son capacidades, no nombres.</strong> systemd dice «necesito a <code>nginx.service</code>»; arje dice «necesito a <em>quien provea</em> esta capacidad». Quién la provee es intercambiable, y el orden de arranque <strong>no se declara: se calcula</strong> — un ordenamiento topológico sobre el grafo de capacidades, que detecta ciclos y descarta lo insatisfacible antes de lanzar nada.</p>

<p><strong>3 — No hay <code>enable</code> ni <code>disable</code>: hay Semilla.</strong> Lo que arranca tu máquina es el árbol <code>genesis</code> de un solo objeto firmable. Cambiar el arranque es editar ese objeto — no crear symlinks que después nadie recuerda por qué están.</p>

<p><strong>4 — El bus de control lo autentica el núcleo.</strong> Cada pedido privilegiado (matar un Ente, congelar, cambiar cuotas) llega con la identidad del proceso que lo pide inyectada por el kernel vía <code>SO_PEERCRED</code> — imposible de falsear — y un verbo clave: <code>RunCard</code> encarna un proceso nuevo <em>con los permisos de quien lo pide</em>, no con los del init. La escalada de privilegios por el bus es imposible <strong>por construcción</strong>, no por política.</p>

<p><strong>5 — El supervisor es soberano.</strong> En systemd, <code>systemctl stop</code> gana siempre. En arje, si la Card dice «esto se supervisa», un stop externo es apenas una señal, y el supervisor decide si el Ente revive. Parar de verdad algo supervisado exige sacarlo del grafo — que es exactamente lo que un atacante con una shell <em>no</em> puede hacer.</p>

<h2>El arranque que se ve: seis actos eran tres</h2>

<p>La prueba más honesta de un init no es un benchmark: es mirar la pantalla desde que apretás el botón. En esa mirada, un arranque Linux típico es una sucesión de parpadeos — logo del firmware, texto de consola, pantalla negra, splash, otra pantalla negra, login. Mirando un arranque real de arje con ese ojo aparecieron <strong>cuatro actos de más</strong> (un cuadrado de color que era un placeholder olvidado, un menú que parpadeaba a cada segundo, texto de consola filtrado sobre el gráfico, un segundo menú redundante). La secuencia que queda son tres actos, sin un cuadro negro entre medio:</p>

<ol class="bucle">
  <li><span>loader</span>El menú-grafo UEFI propio: los sistemas arrancables dibujados como grafo, con degradado y la chakana animada. Elegir acá sí tiene efecto — es <em>antes</em> del kernel.</li>
  <li><span>splash</span>La chakana nativa, dibujada por arje-splash directo al framebuffer, reusando el modo de video que dejó el loader. Sin Plymouth.</li>
  <li><span>greeter</span>El compositor retoma la misma chakana del splash y la deshace sobre el login gráfico. Entre una y otra no hay ni un cuadro negro.</li>
</ol>

<figure class="video">
  <video src="https://gioser.net/blog/medios/arje-arranque.mp4" poster="https://gioser.net/blog/medios/arje-arranque-poster.jpg" width="1600" height="900" autoplay muted loop playsinline preload="metadata" aria-label="Filmado de la pantalla de una laptop: el menú-grafo de arje con tres núcleos de Linux, el texto «entregando el control», la chakana del splash sobre fondo gris y la chakana que se deshace sobre el login con una ciudad de líneas luminosas"></video>
  <figcaption>Diecisiete segundos en tiempo real, filmados con un teléfono sobre la laptop de uso diario el 23 de octubre de 2026: el menú-grafo, «entregando el control», la chakana del splash y el login. Sin edición más allá del recorte.</figcaption>
</figure>


<p>Ese «ni un cuadro negro» costó una cacería medida en milisegundos. El instrumental del motor gráfico mostró que el grueso del hueco entre splash y escritorio era <strong>apagar y re-encender el panel</strong> — unos 1.063 ms de los 1.500 del hueco total. La cura fue no soltar nunca el panel: el splash mantiene la imagen en pantalla hasta que el compositor está listo para el relevo.</p>

<p>La última costura apareció filmando la pantalla en cámara lenta: entre la chakana del splash y la del escritorio quedaban 381 ms de panel encendido sin nada dibujado. El registro del kernel señaló al culpable —el compositor presentaba primero un cuadro liso, herencia de un relevo anterior— y hoy su primer cuadro ya es la chakana. Con un segundo monitor enchufado sí hay un apagón: para encenderlo, el controlador de video tiene que cambiar el reloj de pantalla, y eso apaga el panel un instante. Nadie puede evitarlo, pero sí elegir qué se ve: el cargador detecta la otra pantalla y funde a tiempo al fondo común, así el apagón cae entre dos fondos iguales en vez de cortar el menú.</p>

<figure class="foto">
  <svg viewBox="0 0 640 140" width="100%" role="img" aria-label="Gráfico de barras: el hueco visible del arranque bajó de 1.500 a 389 milisegundos.">
    <text x="0" y="20" style="font:500 14px var(--sans);fill:var(--tinta)">hueco visible splash → escritorio, antes</text>
    <rect x="0" y="30" width="610" height="22" rx="4" style="fill:var(--tinta-tenue)"/>
    <text x="604" y="46" text-anchor="end" style="font:500 13px var(--mono);fill:var(--fondo)">≈ 1.500 ms</text>
    <text x="0" y="88" style="font:500 14px var(--sans);fill:var(--tinta)">después del relevo sin apagar el panel</text>
    <rect x="0" y="98" width="158" height="22" rx="4" style="fill:var(--acento)"/>
    <text x="166" y="114" style="font:500 13px var(--mono);fill:var(--tinta)">389 ms</text>
  </svg>
  <figcaption>Medido en una laptop con Intel Iris Xe, perfilando el primer cuadro del compositor. La causa dominante (~1.063 ms) era el ciclo de apagado y re-encendido del panel eDP; arje-splash ya no lo suelta. Desde el 23 de octubre ni ese resto se ve: la chakana del splash queda en pantalla hasta el primer cuadro del compositor, que ya la trae.</figcaption>
</figure>

<p>Y el menú-grafo se instala con una red de seguridad pensada para máquinas que no tienen a nadie mirándolas: no fija el orden de arranque del firmware —irreversible en una máquina ciega— sino el intento único <code>BootNext</code>, que el firmware borra al usarlo y que un guardián re-arma en cada arranque sano. Un cargador roto consume su intento y la máquina cae sola al arranque de siempre. <strong>Un reset, sin rescate.</strong></p>

<h2>La máquina es un alma; el hardware, un cuerpo</h2>

<p>Hasta acá, arje es un init mejor. Lo que sigue es otra categoría de cosa, y sale de una frase del plan del proyecto: <em>«la máquina es un alma; el hardware es un cuerpo»</em>. El alma es la Semilla firmada, más la historia de sus estados, más un almacén direccionado por contenido donde cada binario vive bajo el hash de sus propios bytes. Cuatro consecuencias, las cuatro funcionando:</p>

<div class="caminos">
  <section>
    <h3>Linaje</h3>
    <p>Cada cambio del sistema —un servicio nuevo, un permiso que se movió— es un commit firmado en una cadena a prueba de bifurcaciones. <code>arjectl log</code> y <code>arjectl diff</code> contestan qué cambió y cuándo; el diff es semántico y nombra los permisos que se movieron.</p>
    <p class="medida">Bootear es hacer checkout: la máquina arranca el commit elegido. Rollback de cero bytes — el estado viejo ya está entero en el almacén.</p>
  </section>
  <section>
    <h3>Cuerpos</h3>
    <p>Un hardware nuevo se levanta pidiendo por la red los bloques del último commit de un alma. Sin servidor, sin nube: por Ethernet crudo, verificando cada bloque contra su hash.</p>
    <p class="medida">Certificado de punta a punta: un nodo B, con sólo los hashes, resucitó el alma del nodo A por el cable y la arrancó como proceso 1.</p>
  </section>
  <section>
    <h3>Jaula</h3>
    <p>El encierro de un proceso se deriva de su Card firmada, no se configura aparte: las rutas que declara se vuelven frontera del kernel (Landlock), y sus permisos, un filtro de llamadas al sistema (seccomp).</p>
    <p class="medida">Sin concesión firmada, jaula máxima. El kernel devuelve «denegado» a lo no declarado — comprobado con la llamada en la mano.</p>
  </section>
  <section>
    <h3>Forense</h3>
    <p>Cada arranque deja una caja negra firmada y encadenada. Si la máquina murió a mitad del boot, el arranque siguiente lo explica solo, en tu idioma.</p>
    <p class="medida"><code>arjectl autopsy</code>: «el boot anterior NO fue limpio — ente=mirada, paso=greeter». Y <code>arjectl blame</code> da el commit que tocó por última vez al culpable.</p>
  </section>
</div>

<figure class="foto">
  <svg viewBox="0 0 640 250" width="100%" role="img" aria-label="Diagrama del linaje: cuatro commits encadenados y firmados; una bifurcación de otra sesión se reconcilia por merge estructural; el commit elegido se arranca con arjectl checkout — bootear es hacer checkout.">
    <defs>
      <marker id="fl-t" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" style="fill:var(--tinta-tenue)"/></marker>
      <marker id="fl-a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" style="fill:var(--acento)"/></marker>
    </defs>
    <!-- cadena principal -->
    <line x1="60" y1="90" x2="180" y2="90" style="stroke:var(--tinta-tenue);stroke-width:2"/>
    <line x1="200" y1="90" x2="320" y2="90" style="stroke:var(--tinta-tenue);stroke-width:2"/>
    <line x1="340" y1="90" x2="460" y2="90" style="stroke:var(--tinta-tenue);stroke-width:2"/>
    <!-- bifurcación de otra sesión, reconciliada -->
    <line x1="198" y1="83" x2="293" y2="45" style="stroke:var(--tinta-tenue);stroke-width:2"/>
    <line x1="308" y1="44" x2="456" y2="79" style="stroke:var(--tinta-tenue);stroke-width:2" marker-end="url(#fl-t)"/>
    <circle cx="300" cy="38" r="8" style="fill:var(--superficie);stroke:var(--tinta-tenue);stroke-width:2"/>
    <text x="300" y="18" text-anchor="middle" style="font:500 11px var(--mono);fill:var(--tinta-tenue)">otra sesión</text>
    <text x="400" y="49" text-anchor="middle" style="font:500 11px var(--mono);fill:var(--tinta-tenue)">merge estructural</text>
    <!-- commits -->
    <circle cx="50" cy="90" r="10" style="fill:var(--superficie);stroke:var(--tinta-tenue);stroke-width:2"/>
    <circle cx="190" cy="90" r="10" style="fill:var(--superficie);stroke:var(--tinta-tenue);stroke-width:2"/>
    <circle cx="330" cy="90" r="10" style="fill:var(--acento-suave);stroke:var(--acento);stroke-width:2.5"/>
    <circle cx="470" cy="90" r="10" style="fill:var(--superficie);stroke:var(--tinta);stroke-width:2"/>
    <text x="50" y="120" text-anchor="middle" style="font:500 11px var(--mono);fill:var(--tinta-suave)">génesis</text>
    <text x="190" y="120" text-anchor="middle" style="font:500 11px var(--mono);fill:var(--tinta-suave)">⚠ net: none → full</text>
    <text x="330" y="70" text-anchor="middle" style="font:500 11px var(--mono);fill:var(--acento)">elegido</text>
    <text x="470" y="120" text-anchor="middle" style="font:500 11px var(--mono);fill:var(--tinta-suave)">− card minga-host</text>
    <text x="488" y="86" style="font:500 11px var(--mono);fill:var(--tinta-tenue)">tip</text>
    <!-- checkout → boot -->
    <line x1="330" y1="102" x2="330" y2="144" style="stroke:var(--acento);stroke-width:2" marker-end="url(#fl-a)"/>
    <text x="318" y="141" text-anchor="end" style="font:500 11px var(--mono);fill:var(--acento)">arjectl checkout</text>
    <rect x="215" y="150" width="230" height="52" rx="6" style="fill:var(--superficie);stroke:var(--acento);stroke-width:1.5"/>
    <text x="330" y="171" text-anchor="middle" style="font:500 13px var(--mono);fill:var(--acento)">boot = checkout</text>
    <text x="330" y="190" text-anchor="middle" style="font:400 12px var(--sans);fill:var(--tinta)">la máquina arranca el commit elegido</text>
    <!-- leyendas -->
    <text x="0" y="234" style="font:500 11px var(--mono);fill:var(--tinta-tenue)">commits firmados — Ed25519 sobre BLAKE3</text>
    <text x="640" y="234" text-anchor="end" style="font:500 11px var(--mono);fill:var(--tinta-tenue)">arjectl log · diff · bisect · blame · autopsy</text>
  </svg>
  <figcaption>El linaje del alma: cada estado del sistema es un commit firmado; lo que diverge en otra sesión se reconcilia por merge estructural, y arrancar es hacer checkout. Acá, un rollback: el tip borró una card, y la máquina arranca el commit anterior — de cero bytes, porque ese estado ya vive entero en el almacén.</figcaption>
</figure>

<p>El paquete completo suena a control de versiones, y lo es: <code>log</code>, <code>diff</code>, <code>checkout</code>, <code>blame</code>, y hasta <code>bisect</code> — una regresión sembrada en una historia de cien commits se encuentra en siete pasos, igual que en git, pero sobre tu sistema operativo. Para quien conozca NixOS: no es eso. No hay lenguaje nuevo ni evaluación — el estado <em>es</em> la Semilla más el almacén, que ya existían. Lo que NixOS no tiene y acá sí: la historia es <strong>firmada y no repudiable</strong>, el diff es <strong>semántico</strong> (objetos, no texto), y dos estados divergentes se <strong>fusionan estructuralmente</strong>.</p>

<p>Esto no nació de un ejercicio teórico. Un día de septiembre, una unidad puesta a mano en la Semilla de un servidor <strong>desapareció</strong>: la Semilla se regenera desde el sistema vivo, y regenerar pisaba. Sin historia, un estado pisado no deja rastro — se notó de casualidad. Con el linaje, esa unidad perdida habría sido una línea de diff: <code>− card minga-host</code>. El init que recuerda existe porque el init que olvida ya costó caro.</p>

<h2>La confianza se firma, no se supone</h2>

<p>Antes de encarnar las piezas críticas del arranque, arje las <strong>atesta</strong>: el hash BLAKE3 de cada binario se contrasta contra concesiones firmadas con Ed25519, ancladas a una llave raíz que vive fuera de la Semilla — de modo que reescribir la Semilla no alcanza para colar un binario ajeno. La misma firma cubre las tres rutas por las que una Semilla puede nacer (instalador, empaquetador, absorción), con una sola implementación: el manifiesto es idéntico salga por donde salga. Y como el almacén direcciona por contenido, el mismo hash que firma la atestación es el nombre con el que un par puede pedir ese binario por la red y <strong>reproducir el sistema exacto</strong>.</p>

<h2>Tus programas no se enteran</h2>

<p>La objeción obvia: «todo el software de escritorio ya asume systemd». Es cierta, y arje la responde con una capa de compatibilidad explícita — no fingiendo ser systemd, sino sirviendo sus interfaces como <strong>borde</strong>, con la lógica real del otro lado:</p>

<div class="tabla" role="region" aria-label="La capa de compatibilidad con systemd" tabindex="0">
<table>
  <thead><tr><th scope="col">lo que el software espera</th><th scope="col">lo que arje le sirve</th></tr></thead>
  <tbody>
    <tr><td><code>org.freedesktop.login1</code> (logind)</td><td>un shim D-Bus con sesiones, asientos, inhibiciones reales y traspaso del master de video — el escritorio gestiona energía y pantalla como siempre</td></tr>
    <tr><td><code>libsystemd</code> / <code>libelogind</code> (la C-ABI que enlazan mutter, polkit, gcr)</td><td>una <code>libelogind.so</code> propia de 28 funciones y una sola dependencia, verificada contra la libsystemd real</td></tr>
    <tr><td><code>org.freedesktop.systemd1</code>, de sistema y de usuario</td><td>cada Ente aparece como «unit»; gnome-session arranca sus servicios con PIDs reales</td></tr>
    <tr><td>journald, <code>journalctl</code></td><td>cada mensaje persiste al almacén por hash; <code>journalctl -o export</code> emite el formato de systemd, re-importable con las herramientas viejas</td></tr>
    <tr><td><code>sd_notify</code>, tmpfiles, binfmt, timers, hostnamed, localed, timedated, resolved, machined, polkit…</td><td>20 binarios de borde, uno por interfaz, con el parseo compartido y testeado en un solo lugar</td></tr>
    <tr><td><code>systemctl</code>, <code>loginctl</code>, <code>journalctl</code> en tus dedos</td><td>el mismo binario de <code>arjectl</code> bajo otro nombre; y si systemd es el init vivo, reenvía al de verdad en vez de mentir</td></tr>
  </tbody>
</table>
</div>

<p>La vara de esa capa fue el software más exigente que existe al respecto: <strong>GNOME 50 arranca y pinta el escritorio completo bajo arje</strong> — gnome-shell, sus servicios de sesión, ibus y portales, verificado en una VM Fedora con captura de pantalla incluida. KDE, que no depende de <code>systemd --user</code>, anduvo antes. Y para migrar una máquina existente está <code>arje-absorb</code>: lee la configuración del init que haya (sysvinit, runit, dinit, OpenRC) en modo sólo-lectura —no destruye nada— y produce una Semilla. En el primer servidor absorbido, 11 de los 20 servicios envueltos quedaron promovidos a daemons supervisados de verdad.</p>

<h2>Medido en metal, no en diapositivas</h2>

<p>El proyecto tiene una regla: lo que no se midió en una máquina de verdad no se afirma. Esta tabla es el estado de arje donde más duele:</p>

<div class="tabla" role="region" aria-label="Arje medido en máquinas reales" tabindex="0">
<table>
  <thead><tr><th scope="col">dónde</th><th scope="col">qué se midió</th></tr></thead>
  <tbody>
    <tr><td>laptop de uso diario</td><td class="propio">arranca todos los días por su propio menú-grafo UEFI; arje-zero como proceso 1 con el escritorio completo encima (compositor DRM, paneles, audio), jornadas enteras de uptime; suspensión real medida en 5,9 s; apagado y reinicio por el bus con su motivo registrado</td></tr>
    <tr><td>servidor de producción</td><td class="propio">una Semilla de 26 Entes sosteniendo SSH, el servidor web y el git público; el apagado ordenado baja el árbol entero en cascada, hojas primero</td></tr>
    <tr><td>FreeBSD 14.5</td><td class="propio"><code>ps -p 1</code> contesta <code>arje-zero</code> — no delegó: ES el init, con los mecanismos reescritos sobre kqueue, jails y devd. El testigo del apagado es el hipervisor, que ve la máquina «off»; el del reinicio, el reloj de arranque del kernel</td></tr>
    <tr><td>dos nodos por Ethernet crudo</td><td class="propio">la resurrección completa: el nodo B pide por el cable los bloques del alma de A, los verifica contra sus hashes, y arranca ese sistema como proceso 1</td></tr>
    <tr><td>vigilancia dura</td><td class="propio">un perro guardián de hardware acaricia <code>/dev/watchdog</code> desde el bucle del proceso 1: si el init se cuelga, el kernel reinicia en vez de dejar la máquina muerta</td></tr>
  </tbody>
</table>
</div>

<p>Y la honestidad del método incluye contar los golpes. El más instructivo no fue de arje: en un servidor con init clásico, <code>reboot</code> no hacía <strong>nada</strong> — ni error, ni mensaje. La herramienta escribía ocho bytes en un archivo de control que ningún proceso tenía abierto, y salía con éxito. <em>El peor modo de fallar.</em> Arje tuvo los suyos (un deadlock del proceso 1 que un comentario ya advertía; 2.466 zombies por una máscara de señales que <code>execve</code> no restaura), y cada uno terminó convertido en un test y en una línea de estas tablas. Ningún init es inocente; la diferencia es si sus muertes dejan autopsia.</p>

<h2>Lo que arje tiene y systemd no</h2>

<div class="tabla" role="region" aria-label="Capacidades de arje sin equivalente en systemd" tabindex="0">
<table>
  <thead><tr><th scope="col">capacidad</th><th scope="col">qué significa</th></tr></thead>
  <tbody>
    <tr><td class="propio">atestación de arranque</td><td>firmas Ed25519 sobre el hash de cada binario crítico, con ancla soberana externa que vence a una Semilla reescrita</td></tr>
    <tr><td class="propio">el sistema como commit</td><td><code>log</code> · <code>diff</code> · <code>checkout</code> · <code>bisect</code> · <code>blame</code> sobre el estado del sistema operativo; rollback de cero bytes</td></tr>
    <tr><td class="propio">caja negra del boot</td><td>cada arranque deja su vuelo firmado; <code>arjectl autopsy</code> explica el boot que murió, en tres idiomas</td></tr>
    <tr><td class="propio">resurrección por el cable</td><td>un cuerpo nuevo se levanta pidiendo los bloques del alma por Ethernet crudo, sin TCP/IP ni servidor</td></tr>
    <tr><td class="propio">re-floor</td><td>si el proveedor de una capacidad cae, sus dependientes no se descartan: quedan aparcados y se re-erigen solos en orden topológico cuando vuelve</td></tr>
    <tr><td class="propio">escalada imposible por construcción</td><td>la identidad en el bus la inyecta el kernel; encarnar algo nuevo hereda los permisos de quien lo pide, nunca los del init</td></tr>
    <tr><td class="propio">auditoría con cadena de hashes</td><td>quién pidió qué —spawns, kills, energía, cuotas— anclado al almacén de contenido, consultable</td></tr>
    <tr><td class="propio">reglas con razonador</td><td>un cerebro declarativo («si este proceso pasa del 80 % de CPU 30 s, bajale el peso») que cristaliza reglas de patrones observados, con su propia auditoría</td></tr>
  </tbody>
</table>
</div>

<h2>Lo que decide no hacer</h2>

<p>La otra mitad del diseño es la lista de lo que arje <strong>rechaza</strong> con razones escritas, porque un init que absorbe todo ya existe y es el problema. No hay <code>enable</code>/<code>disable</code> (la Semilla <em>es</em> el modelo), no hay drop-ins ni recarga en caliente de unidades (inmutable después del boot: menos superficie, más razonabilidad), no hay gestor de usuarios ni de particiones ni de contenedores dentro del init (eso es de otras piezas de la suite), no hay matador heurístico de procesos por memoria (hay límites y reglas con política explícita, no una heurística que decide por vos). Cada «no» está documentado con su porqué — y ésa es quizás la diferencia cultural más grande con el software que vino a reemplazar.</p>

<aside class="ficha" aria-labelledby="ficha-arje">
  <h2 id="ficha-arje">Lo medimos</h2>
  <dl>
    <div><dt>Líneas de Rust, dominio completo</dt><dd>48.171</dd></div>
    <div><dt>Piezas de software (crates)</dt><dd>31</dd></div>
    <div><dt>Tests del dominio</dt><dd>504</dd></div>
    <div><dt>Binarios de compatibilidad systemd</dt><dd>20</dd></div>
    <div><dt>Funciones de la C-ABI sd-login servidas</dt><dd>28</dd></div>
    <div><dt>Cuadros negros entre splash y escritorio</dt><dd>ninguno (eran 1,5 s)</dd></div>
    <div><dt>Entes de la Semilla del servidor de producción</dt><dd>26</dd></div>
    <div><dt>Suspensión medida en metal</dt><dd>5,9 s</dd></div>
    <div><dt>Regresión hallada por <code>bisect</code> en 100 commits</dt><dd>≤ 7 pasos</dd></div>
  </dl>
  <p>Conteos hechos sobre el repositorio de tawasuyu el 22 de octubre de 2026 y sobre el servidor el 23; las medidas de metal, en las máquinas y fechas que nombra el texto.</p>
</aside>

<h2>Lo que todavía no</h2>

<ul>
  <li><strong>Un segundo monitor todavía parpadea.</strong> Arrancar con un monitor externo enchufado apaga el panel un instante —es el hardware, y el cargador lo disimula fundiendo al fondo—; y enchufarlo con la sesión abierta hoy cuesta cuatro parpadeos donde alcanzaría uno.</li>
  <li><strong>El relevo sin parpadeo del splash al escritorio está certificado sobre gráficos Intel.</strong> AMD y el driver nuevo <code>xe</code> no están verificados todavía; NVIDIA propietario queda explícitamente fuera del camino sin costuras.</li>
  <li><strong>El logind de compatibilidad modela una sesión única.</strong> Cambio de consola virtual, multi-sesión, idle y tapa están servidos a medias; es el hueco que más se siente en el escritorio y está nombrado como tal en el plan.</li>
  <li><strong>No hay red declarativa ni reglas udev.</strong> arje trae un alzado de red mínimo y traduce los eventos de hardware a capacidades; una topología de red compleja hoy se resuelve con las herramientas de siempre.</li>
  <li><strong>El linaje no versiona tus datos.</strong> Versiona el sistema — la Semilla, las unidades, los binarios—; prometer «viaje en el tiempo de todo» sería mentir, y el plan lo dice con esas palabras.</li>
  <li><strong>La atestación arranca en modo aviso.</strong> Pasarla a modo estricto es una ceremonia del operador —generar su llave raíz y anclarla—, deliberadamente manual: estrenar atestación nunca debe dejar una máquina sin arranque.</li>
  <li><strong>En FreeBSD, arje es el init, pero la paridad no es total:</strong> los límites de recursos que en Linux son cgroups allá se degradan con aviso, y quedan piezas nombradas por escribir.</li>
</ul>

<h2>Cómo verlo</h2>

<p>Arje vive en la región raíz del repositorio de tawasuyu —<a href="https://git.tawasuyu.net/tawasuyu/tawasuyu">git.tawasuyu.net</a>, en un servidor propio— bajo <code>03_ukupacha/arje</code>, y también como repositorio propio que compila solo: <a href="https://git.tawasuyu.net/tawasuyu/arje">git.tawasuyu.net/tawasuyu/arje</a>. El documento de migración, <code>DE-SYSTEMD-A-ARJE.md</code>, mapea verbo a verbo lo que sabés de systemd a lo que arje hace distinto; los planes y sus mediciones están al lado, con fechas y números, tal como salieron.</p>
]]></content:encoded>
  </item>
  <item>
    <title>Tawasuyu: un sistema soberano de punta a punta, construido sobre la chakana andina</title>
    <link>https://gioser.net/blog/tawasuyu-cuatro-regiones/</link>
    <guid isPermaLink="true">https://gioser.net/blog/tawasuyu-cuatro-regiones/</guid>
    <pubDate>Fri, 16 Oct 2026 09:00:00 -0500</pubDate>
    <dc:creator>Redacción Gioser</dc:creator>
    <category>tawasuyu · Soberanía</category>
    <description>tawasuyu, la suite de software en Rust que busca la soberanía en cada capa de la computadora —del sistema operativo a la identidad— y se ordena como la chakana: cuatro regiones, un puente en el centro y aplicaciones que son instituciones andinas escritas como software.</description>
    <enclosure url="https://gioser.net/blog/medios/tawasuyu-escritorio.jpg" type="image/jpeg" length="100132"/>
    <content:encoded><![CDATA[<p class="lede">Prendés tu computadora y, antes de que veas nada, ya decidieron por vos: qué arranca, quién dibuja la pantalla, qué motor abre las páginas, dónde viven tus archivos y quién puede darte de baja la cuenta que dice quién sos. <strong>tawasuyu</strong> nace de una pregunta incómoda: <em>¿qué haría falta para que cada una de esas capas fuera tuya?</em> La respuesta ocupa más de mil doscientas piezas de software. Y su plano no viene de Silicon Valley: viene de los Andes.</p>


<figure class="foto">
  <img src="https://gioser.net/blog/medios/tawasuyu-andes.jpg" alt="Dos cruces de piedra en una cumbre andina al amanecer: a la izquierda la de takana, de ladrillos ocres; a la derecha la chakana de tawasuyu, con los colores del arcoíris y un hueco de luz en el centro" width="1600" height="900" loading="eager">
  <figcaption>Ilustración: las marcas de takana y de tawasuyu talladas en piedra frente a un nevado.</figcaption>
</figure>

<h2>Qué es tawasuyu</h2>

<p>Tawasuyu es una suite de software vertical escrita en Rust. Entre sus piezas hay un <strong>sistema operativo</strong> que arranca directamente sobre el hardware, sin Linux debajo; un <strong>motor gráfico</strong> propio, Llimphi; un <strong>escritorio</strong> con su gestor de ventanas; un <strong>navegador web</strong> con motor propio, sin Chromium ni WebKit; un entorno de <strong>escritura</strong> donde un mismo texto vive en varios idiomas y tonos; un <strong>ERP</strong>, un motor de <strong>astronomía</strong>, <strong>correo</strong>, <strong>música</strong>, <strong>video</strong> y una <strong>historia clínica</strong>.</p>

<p>Lo raro no es la cantidad. Es que nada de eso alquila sus cimientos: todo se apoya en el mismo formato, la misma identidad y el mismo motor que dibuja, y ninguno de ellos tiene un dueño que no seas vos.</p>

<h2>Soberanía, capa por capa</h2>

<p>La palabra se gastó en los discursos, así que conviene bajarla a algo que se pueda revisar. En una computadora común, cada capa tiene un dueño que no es quien la usa. En tawasuyu, cada una tiene una pieza propia que la reemplaza:</p>

<div class="tabla" role="region" aria-label="Quién manda en cada capa, y qué pone tawasuyu en su lugar" tabindex="0">
<table>
  <thead><tr><th scope="col">Capa</th><th scope="col">Quién manda, normalmente</th><th scope="col">En tawasuyu</th></tr></thead>
  <tbody>
    <tr><td>El arranque</td><td>el núcleo y el sistema de otro</td><td><span class="pieza">wawa</span>, un sistema operativo propio, y <span class="pieza">arje</span>, el primer proceso (init)</td></tr>
    <tr><td>El píxel</td><td>Qt, GTK, Flutter o un navegador escondido</td><td><span class="pieza">Llimphi</span>, un motor gráfico que dibuja cada botón de la suite</td></tr>
    <tr><td>La web</td><td>Chromium o WebKit, casi siempre</td><td><span class="pieza">puriy</span>, un navegador con su propio motor de JavaScript</td></tr>
    <tr><td>Quién sos</td><td>una cuenta que un tercero te da y te puede quitar</td><td><span class="pieza">agora</span>: tu identidad es una clave que generás vos, en tu máquina</td></tr>
    <tr><td>Tus archivos</td><td>un índice central que se puede confiscar o censurar</td><td>cada archivo se nombra por su contenido: el nombre es la prueba de que no lo cambiaron</td></tr>
    <tr><td>La red</td><td>servidores en el medio</td><td>conexión entre pares; el sistema propio habla además un protocolo de red propio</td></tr>
    <tr><td>La historia del código</td><td>una plataforma de terceros</td><td><span class="pieza">minga</span>, un control de versiones propio, y el código en un servidor del autor</td></tr>
    <tr><td>Los formatos ajenos</td><td>el programa del fabricante</td><td>46 puentes declarados —PDF, Excel, Word, Photoshop, torrent…— que leen y escriben sin meterse en el núcleo</td></tr>
  </tbody>
</table>
</div>

<p>Y la regla que ordena la tabla es una sola: <strong>lo de afuera entra por un puente, nunca al centro</strong>. Un PDF se abre, una planilla se importa, un sitio web se visita; pero adentro todo trabaja en el formato propio, y si mañana desaparece el fabricante de ese formato, lo tuyo sigue siendo legible.</p>

<h2>La sobrevivencia no es sólo de la persona</h2>

<p>Hasta acá, esto podría ser el sueño de alguien que quiere encerrarse en su máquina. Pero la soberanía individual tiene un límite conocido: una persona sola no sostiene un camino, ni un registro, ni una decisión. Y ahí es donde el proyecto mira hacia los Andes.</p>

<p>Los pueblos andinos sostuvieron durante miles de años caminos que cruzaban un continente y terrazas que todavía dan cosecha, sin moneda ni escritura alfabética. Lo que los sostuvo no fue un aparato técnico, sino una forma de organizarse: <em>ayni</em>, la reciprocidad exacta y medible; <em>minka</em>, el trabajo voluntario para el común; y el <em>ayllu</em>, <strong>la comunidad soberana como unidad</strong>, en lugar del individuo aislado.</p>

<p>Tawasuyu traduce esa idea a criptografía. Un archivo nombrado por su contenido no tiene un índice central que alguien pueda confiscar. Una identidad que es una clave no necesita un registro maestro que la autorice o la dé de baja. Y una comunidad que decide con un <strong>umbral de firmas</strong> —tantos de sus miembros tienen que estar de acuerdo— no depende de quién sea el dueño del servidor. Es la misma premisa, escrita esta vez en Rust.</p>

<h2>Cuatro regiones, un ciclo</h2>

<p>El nombre es el plano. <em>Tawa</em> es cuatro en quechua y <em>suyu</em> es región: tawasuyu quiere decir <strong>cuatro regiones</strong>. El repositorio entero está partido en cuatro, y cada parte corresponde a una fase de lo que le pasa a la información: se percibe, se conoce, se actúa con ella y se sostiene.</p>

<div class="tabla" role="region" aria-label="Las cuatro regiones de tawasuyu" tabindex="0">
<table>
  <thead><tr><th scope="col">Región</th><th scope="col">Fase</th><th scope="col">Qué vive ahí</th></tr></thead>
  <tbody>
    <tr><td><span class="pieza">00_unanchay</span></td><td class="propio">Percibir</td><td>Lo que capta señales: el navegador, las notas, el lenguaje, la escritura, el contraste de noticias.</td></tr>
    <tr><td><span class="pieza">01_yachay</span></td><td class="propio">Conocer</td><td>Lo que modela y calcula: astronomía, simulación, física, el ERP, la historia clínica, la verificación de afirmaciones.</td></tr>
    <tr><td><span class="pieza">02_ruway</span></td><td class="propio">Hacer</td><td>Lo que actúa: el motor gráfico, el escritorio, la terminal, la música, el video, el correo, los juegos.</td></tr>
    <tr><td><span class="pieza">03_ukupacha</span></td><td class="propio">Raíz</td><td>Lo que sostiene todo: el sistema operativo, el arranque, la identidad, la red.</td></tr>
  </tbody>
</table>
</div>

<p><em>Yachay</em> es saber y <em>ruway</em> es hacer. <em>Unanchay</em> se emparenta con la señal y con darse cuenta de ella. <em>Uku pacha</em> es, en la cosmovisión andina, el mundo de adentro, el de abajo: el lugar de las raíces. No es casual que la soberanía empiece ahí: quien no es dueño de la raíz no es dueño de nada de lo que crece encima.</p>

<p>Y no es una división administrativa. Mover un programa de región <strong>cambia lo que es</strong>. Tawasuyu tiene dos programas que trabajan con noticias: <em>watuy</em> cosecha afirmaciones y las pone lado a lado, y vive en <em>percibir</em>; <em>iniy</em> (en quechua, creer) las verifica, y vive en <em>conocer</em>. Recoger una afirmación no es darla por cierta, y el código no deja que se confundan.</p>

<h2>La chakana: todo pasa por el puente</h2>
<figure class="foto">
  <img src="https://gioser.net/blog/medios/tawasuyu-escritorio.jpg" alt="El escritorio de tawasuyu: la chakana de colores con su hueco circular en el centro de la pantalla, cruzada por dos ejes de luz; a la izquierda los escritorios y las aplicaciones, a la derecha el panel del taller con la lista de programas compilados" width="1600" height="900" loading="lazy">
  <figcaption>El escritorio de tawasuyu, tal como se ve hoy en la máquina del autor: la chakana al centro, y a los costados los paneles de la suite.</figcaption>
</figure>


<p>El logo es una chakana, la cruz escalonada andina con un hueco circular en el centro. Está tallada en piedra desde Chavín y Tiwanaku, y sigue apareciendo en tejidos que alguien hace hoy. Su nombre viene de <em>chaka</em>, <strong>puente</strong>.</p>

<p>En tawasuyu la chakana no es un adorno: es el diagrama. Las cuatro regiones son sus cuatro brazos, y en el centro está el puente. La regla que eso dibuja es estricta: <strong>nada se comunica saltando; todo pasa por el medio</strong>. Es la misma regla de los formatos ajenos, vista desde arriba: lo que cruza, cruza por un lugar declarado, donde se lo puede mirar.</p>

<h2>Apps que se entrelazan como un ayllu</h2>

<p>Las aplicaciones de tawasuyu no se piensan como programas sueltos. La documentación del proyecto lo dice en una línea: son <strong>las instituciones andinas escritas como software</strong>. Y casi todas hacen lo mismo con una institución distinta: le sacan el intermediario.</p>

<div class="tabla" role="region" aria-label="Instituciones andinas y lo que hacen en tawasuyu" tabindex="0">
<table>
  <thead><tr><th scope="col">Nombre</th><th scope="col">La tradición</th><th scope="col">En tawasuyu</th></tr></thead>
  <tbody>
    <tr><td><span class="pieza">ayni</span></td><td>la reciprocidad: lo que te doy hoy vuelve cuando me toque</td><td>crédito entre conocidos, sin interés y sin banco ni servidor</td></tr>
    <tr><td><span class="pieza">mit'a</span></td><td>el trabajo por turnos para el común</td><td>el trabajo comunitario atestado se convierte en crédito recíproco</td></tr>
    <tr><td><span class="pieza">minga</span></td><td>la faena voluntaria de todos</td><td>la colaboración entre pares y el control de versiones propio</td></tr>
    <tr><td><span class="pieza">tantanakuy</span></td><td>reunirse</td><td>la asamblea: convocatoria, quórum, voto y acta firmada, sin una plataforma que la aloje</td></tr>
    <tr><td><span class="pieza">khipu</span></td><td>las cuerdas anudadas que guardaban la memoria</td><td>notas que se refuerzan entre sí, o se olvidan, guardadas en tu máquina</td></tr>
    <tr><td><span class="pieza">siqi</span></td><td>las líneas que unían cada lugar con el centro</td><td>automatizaciones: cada regla es un dato que se puede firmar</td></tr>
    <tr><td><span class="pieza">tampu</span></td><td>los depósitos a lo largo del camino</td><td>los objetos compartidos de una comunidad</td></tr>
    <tr><td><span class="pieza">chasqui</span></td><td>el mensajero de postas</td><td>el que lleva los datos de un programa a otro</td></tr>
  </tbody>
</table>
</div>

<p>Y se entrelazan como en un ayllu: el trabajo que deja constancia en <em>tampu</em> se vuelve crédito en <em>ayni</em>, la asamblea de <em>tantanakuy</em> firma su acta como comunidad, y esa acta queda en un registro público. Ninguno de esos pasos necesita pedirle permiso a una empresa.</p>

<h2>Agora y el sello del ayllu</h2>

<p>Esa idea tiene su lugar propio en <strong>agora</strong>, la plaza de la identidad. Una comunidad tiene su <strong>constitución</strong> y su propio <strong>sello</strong>, que sólo se estampa cuando firman los miembros que ella misma fijó. La persona es soberana y la comunidad puede firmar como una sola, sin que nadie firme en nombre ajeno. Agora merece un artículo propio, y lo tendrá.</p>

<h2>Un homenaje</h2>

<p>Cuando la conquista prohibió las asambleas y persiguió la lengua, la forma andina de organizarse no se perdió: el quechua se sigue hablando y la cruz escalonada se sigue tejiendo. Es, a su manera, la prueba de soberanía más larga que existe: lo que una comunidad sostiene sobrevive a quien quiso quitárselo.</p>

<p>Tawasuyu es un <strong>homenaje a esa arquitectura</strong>. No es una bandera: el quechua es la lengua de muchos pueblos y atraviesa fronteras, y el proyecto no habla en nombre de ninguno. Aprende de ellos. Toma la idea que más tiempo resistió —que lo que perdura no es lo que un dueño guarda en su servidor, sino lo que una comunidad sostiene— y la escribe en el lugar donde hoy se decide quién manda: el software.</p>

<aside class="ficha" aria-labelledby="ficha-tawasuyu">
  <h2 id="ficha-tawasuyu">Lo medimos</h2>
  <dl>
    <div><dt>Piezas de software (crates) en el espacio de trabajo</dt><dd>1.210</dd></div>
    <div><dt>Carpetas de dominio: percibir · conocer · hacer · raíz</dt><dd>7 · 11 · 37 · 8</dd></div>
    <div><dt>Carpetas de núcleos compartidos</dt><dd>104</dd></div>
    <div><dt>Puentes hacia formatos ajenos</dt><dd>46</dd></div>
    <div><dt>Familias de aplicaciones</dt><dd>4</dd></div>
    <div><dt>Lenguaje</dt><dd>Rust</dd></div>
  </dl>
  <p>Conteo hecho sobre el repositorio el 16 de octubre de 2026. El sistema operativo propio se compila aparte y no entra en el número de piezas.</p>
</aside>

<h2>Lo que todavía no</h2>

<ul>
  <li><strong>El sistema operativo propio todavía no reemplaza a Linux en el uso diario.</strong> Hoy el escritorio de tawasuyu corre sobre un núcleo Linux y sus controladores; la raíz propia existe y arranca, pero aún no carga con todo.</li>
  <li><strong>El navegador propio todavía no abre toda la web.</strong> Su motor de JavaScript pasa el 13,1 % de la batería oficial del lenguaje (Test262), y el navegador el 22,1 % de las subpruebas de la plataforma web (WPT) que ya se le corren. Crece cada semana, y los números se publican tal como salen.</li>
  <li><strong>El hardware no es soberano.</strong> El procesador, la placa de video y su firmware siguen siendo de quien los fabricó. tawasuyu empieza donde termina el silicio.</li>
  <li><strong>Los nombres cuestan al principio.</strong> Quien llega no sabe qué es <em>nakui</em> o <em>kamachiq</em> sin leer su ficha, y el quechua de algunas pantallas no lo revisó todavía un hablante. La revisión es bienvenida.</li>
</ul>

<h2>Cómo verlo</h2>

<p>El código está en <a href="https://git.tawasuyu.net/tawasuyu/tawasuyu">git.tawasuyu.net</a> —en un servidor propio, no en una plataforma ajena— y el mapa completo, en <a href="https://tawasuyu.net">tawasuyu.net</a>. Para comprobar lo que dice este artículo, basta con abrir la raíz del repositorio: las cuatro regiones son lo primero que aparece.</p>
]]></content:encoded>
  </item>
  <item>
    <title>¿Qt, GTK, Flutter, Electron? No: un motor gráfico de cero, enteramente en Rust</title>
    <link>https://gioser.net/blog/llimphi-motor-grafico-de-cero/</link>
    <guid isPermaLink="true">https://gioser.net/blog/llimphi-motor-grafico-de-cero/</guid>
    <pubDate>Mon, 12 Oct 2026 19:00:00 -0500</pubDate>
    <dc:creator>Redacción Gioser</dc:creator>
    <category>tawasuyu · Llimphi</category>
    <description>Llimphi, el motor gráfico de tawasuyu escrito en Rust: por qué no usa Qt, GTK ni Flutter, cómo pinta por cuatro caminos distintos y qué midió el equipo.</description>
    <enclosure url="https://gioser.net/blog/medios/llimphi-portada.jpg" type="image/jpeg" length="42477"/>
    <content:encoded><![CDATA[<p class="lede">Cada vez que abres una aplicación, algo tiene que dibujar en tu pantalla cada botón, cada letra y cada ventana, decenas de veces por segundo. Ese algo es un motor gráfico, y casi nadie hace el suyo: la mayor parte del software del mundo se pinta con Qt, GTK, Flutter o Electron. Tawasuyu, la suite de software con nombres en quechua que se escribe en el taller de Gioser, decidió no pedir prestado.</p>

<p>Su motor se llama <strong>Llimphi</strong>, que en quechua quiere decir <em>color</em>, <em>brillo</em>, <em>pigmento</em>. Con él se dibuja la suite entera: el escritorio, el editor, el reproductor de video, los paneles de control y la interfaz del sistema operativo propio del proyecto. Hoy son <strong>276 piezas de la suite</strong> las que se pintan con Llimphi.</p>

<figure class="video">
  <video src="https://gioser.net/blog/medios/llimphi-showreel.mp4" poster="https://gioser.net/blog/medios/llimphi-poster.jpg" width="1600" height="900" autoplay muted loop playsinline preload="metadata" aria-label="Una terminal donde se escribe llimphi se transforma en un campo de texto de vidrio; al enviarlo se despliegan controles, la página se desliza al cielo de cosmos, a un pasillo en primera persona que termina en una fuente, y por el agua a un vuelo sobre un mundo voxel infinito bajo un nevado, donde un muñequito festeja mientras una mano escribe llimphi"></video>
  <figcaption>Quince segundos y medio de Llimphi. Todo lo que se ve lo dibuja el motor, cuadro a cuadro: los controles, el cielo de cosmos, el pasillo de supay, el mundo voxel infinito y la mano.</figcaption>
</figure>

<h2>Por qué no usar uno que ya existe</h2>

<p>Hasta mayo de 2026, tawasuyu se dibujaba con GPUI, el motor del editor Zed. El 26 de mayo lo retiraron por completo, y la razón no fue capricho: el proyecto tiene su propio sistema operativo, <em>wawa</em>, que arranca directamente sobre el hardware, sin Linux debajo. Ningún motor existente sabe dibujar ahí.</p>

<p>Qt, GTK y Flutter dan por hecho que hay un sistema operativo convencional, con su gestor de ventanas, sus fuentes instaladas y su manejo de memoria. Llimphi se diseñó desde el primer día para pintar tanto en una ventana de escritorio como en la memoria de video de un kernel recién encendido. Esa exigencia obligó a escribirlo desde cero.</p>

<h2>Qué quiere decir «de cero»</h2>

<p>Conviene ser precisos, porque es la pregunta que hace todo programador. Llimphi no reinventó cada pieza. Igual que Flutter se apoya en Skia y GTK en Cairo, Llimphi usa cuatro proyectos libres de la comunidad de Rust para los trabajos más especializados. Lo que es propio es todo lo demás: la forma en que una aplicación describe su pantalla, cómo reacciona a cada clic, los componentes y los caminos para llegar a los píxeles.</p>

<div class="tabla" role="region" aria-label="Qué es propio y qué viene de la comunidad" tabindex="0">
<table>
  <thead><tr><th scope="col">Trabajo</th><th scope="col">Quién lo hace</th></tr></thead>
  <tbody>
    <tr><td>Hablar con la tarjeta de video</td><td><span class="pieza">wgpu</span> · comunidad</td></tr>
    <tr><td>Trazar curvas y rellenos con suavizado</td><td><span class="pieza">vello</span> · comunidad</td></tr>
    <tr><td>Calcular dónde va cada caja (flexbox y grid)</td><td><span class="pieza">taffy</span> · comunidad</td></tr>
    <tr><td>Componer texto: árabe, chino, emoji, ligaduras</td><td><span class="pieza">parley</span> · comunidad</td></tr>
    <tr><td>El ciclo de vida de cada aplicación</td><td class="propio">Llimphi</td></tr>
    <tr><td>Componentes, temas, animación, accesibilidad</td><td class="propio">Llimphi</td></tr>
    <tr><td>Pintar sin tarjeta de video, dentro del kernel</td><td class="propio">Llimphi</td></tr>
    <tr><td>Aislar una aplicación y pintar su dibujo desde afuera</td><td class="propio">Llimphi</td></tr>
  </tbody>
</table>
</div>

<p>Las cuatro piezas de la comunidad también están escritas en Rust. Por eso el titular dice «enteramente en Rust» y lo sostiene.</p>

<h2>Cómo piensa una aplicación de Llimphi</h2>

<p>Llimphi sigue la arquitectura de Elm, un lenguaje conocido por sus aplicaciones que casi no fallan. La idea es simple: la aplicación no modifica la pantalla, sino que la describe. Cada vez que pasa algo, el motor recorre seis pasos:</p>

<ol class="bucle">
  <li><span>input</span>Llega un clic, una tecla o un gesto.</li>
  <li><span>update</span>La aplicación calcula su nuevo estado.</li>
  <li><span>view</span>Describe cómo debería verse con ese estado.</li>
  <li><span>layout</span>El motor calcula la posición de cada caja.</li>
  <li><span>raster</span>Convierte esa descripción en píxeles.</li>
  <li><span>present</span>Muestra el cuadro terminado.</li>
</ol>

<p>Como nadie toca la pantalla directamente, no hay dos partes del programa peleándose por el mismo botón. Es la misma razón por la que este estilo se volvió popular en la web con React, solo que acá corre nativo y sin navegador en el medio.</p>

<h2>Un pincel, cuatro caminos hasta tu pantalla</h2>

<p>La parte más inusual de Llimphi es que el mismo dibujo puede llegar a la pantalla por caminos completamente distintos, según dónde corra la aplicación. El equipo no se conformó con que «se vea parecido»: puso cada camino lado a lado y contó los píxeles.</p>

<div class="caminos">
  <section>
    <h3>Con tarjeta de video</h3>
    <p>El camino de todos los días en el escritorio.</p>
    <p class="medida">Es la referencia contra la que se mide el resto.</p>
  </section>
  <section>
    <h3>Solo con el procesador</h3>
    <p>El que usa el kernel de wawa, que no tiene controlador de video.</p>
    <p class="medida">Rellenos y capas idénticos bit a bit. El texto con acentos puede variar, porque el kernel solo trae tres fuentes.</p>
  </section>
  <section>
    <h3>Por mensaje</h3>
    <p>Una aplicación aislada no toca la pantalla: manda su dibujo como mensaje y el sistema lo pinta por ella.</p>
    <p class="medida">0 píxeles de diferencia en las cuatro escenas de prueba.</p>
  </section>
  <section>
    <h3>Para teléfonos</h3>
    <p>Un camino que funciona en chips gráficos móviles sin cómputo general, como el Mali-G57.</p>
    <p class="medida">Ningún píxel difiere en más de 1/255 sobre 19.200.</p>
  </section>
</div>

<p>Que el camino «por mensaje» dé cero diferencia tiene una consecuencia práctica: una aplicación puede vivir encerrada, sin ningún permiso para tocar la pantalla, y aun así verse exactamente igual. Es seguridad que no se paga en apariencia.</p>

<h2>Lo que ya trae</h2>

<ul class="trae">
  <li><strong>Cerca de ochenta componentes</strong>: botones, tablas, editores de texto con varios cursores, grafos de nodos, divisores de paneles, calendarios y más.</li>
  <li><strong>Once módulos</strong> que combinan componentes en piezas de aplicación completas.</li>
  <li><strong>Texto de verdad</strong>: escritura de derecha a izquierda, caracteres chinos, emoji, ligaduras y métodos de entrada para idiomas asiáticos.</li>
  <li><strong>Accesibilidad</strong>: cada elemento puede declarar qué es y cómo se llama, y las pruebas lo consultan como lo haría un lector de pantalla.</li>
  <li><strong>Pruebas contra imagen</strong>: una pantalla se compara con su versión aprobada, y cualquier cambio inesperado hace fallar la prueba.</li>
  <li><strong>Un motor 3D de vóxeles</strong> que se monta dentro de la misma interfaz, como un componente más.</li>
</ul>

<aside class="ficha" aria-labelledby="ficha-titulo">
  <h2 id="ficha-titulo">Lo medimos</h2>
  <dl>
    <div><dt>Piezas de software (crates)</dt><dd>150</dd></div>
    <div><dt>Líneas de Rust, con ejemplos y pruebas</dt><dd>239.173</dd></div>
    <div><dt>Piezas de tawasuyu que dibujan con Llimphi</dt><dd>276</dd></div>
    <div><dt>Componentes listos para usar</dt><dd>79</dd></div>
    <div><dt>Diferencia entre pintar directo y por mensaje</dt><dd>0 px</dd></div>
    <div><dt>Licencia</dt><dd>MIT o Apache-2.0</dd></div>
  </dl>
  <p>Conteo hecho sobre el repositorio el 12 de octubre de 2026.</p>
</aside>

<h2>Lo que todavía no</h2>

<p>Un motor que promete demasiado pierde la confianza de quien lo prueba, así que vale decir también lo que falta:</p>

<ul>
  <li>El camino para teléfonos está probado en hardware real, pero <strong>ninguna aplicación publicada lo usa todavía</strong>. Las versiones de Android actuales van por otro camino que no funciona en todos los chips.</li>
  <li>Fuera de sus tres fuentes integradas, el texto puede verse distinto en el kernel y en el escritorio. El origen está identificado: sin un sistema operativo debajo, no hay de dónde sacar más fuentes.</li>
  <li>Parte de Llimphi ya está publicada en <a href="https://crates.io/crates/llimphi">crates.io</a>, el registro oficial de Rust, pero la publicación está incompleta y algunas piezas recientes todavía no subieron.</li>
</ul>

<h2>Cómo probarlo</h2>

<p>Para quien programa en Rust, la entrada es un solo paquete:</p>

<pre><code>cargo add llimphi</code></pre>

<p>El paquete reúne el núcleo, los temas y el motor 3D. Para el resto, la mejor demostración es tawasuyu mismo: cada ventana de la suite es una aplicación de Llimphi.</p>
]]></content:encoded>
  </item>
</channel>
</rss>
