MarkTechPostPublicación de la fuente

Reason Machines publica el código abierto de Aspen, un servidor Git creado para agentes de IA

Reason Machines ha lanzado Aspen, un servidor Git de código abierto para tráfico de agentes de IA. Está dirigido a repositorios a los que cientos de agentes hacen push a la vez.

Reason Machines ha lanzado Aspen, un servidor Git de código abierto para tráfico de agentes de IA. Está dirigido a repositorios a los que cientos de agentes hacen push a la vez. Aspen implementa de forma independiente el diseño que OpenAI describió para Pando.

TL;DR

  • Tamaño: Un solo binario de Rust. Las ramas viven en PostgreSQL (o SQLite), los packs viven en almacenamiento de objetos.
  • Se ejecuta en: Un portátil (aspen dev), un solo host vía Docker Compose, o Helm y nubes con Terraform.
  • Rendimiento: Los pushes a ramas diferentes nunca se esperan entre sí, y los fetch reutilizan los packs almacenados.
  • Lo mejor: 567 pushes por segundo sostenidos durante 5 minutos en un solo servidor de 8 núcleos (autoinformado).
  • Lo peor: Aterrizar en main se ejecuta a unos 4 por segundo, y el proyecto está en fase pre-alfa.
  • En resumen: Lo mejor: las escrituras por rama eliminan el límite de push por repositorio. Lo peor: sin releases, sin interfaz web, y la puerta de durabilidad de 24 horas no se cumple.

¿Qué es Aspen?

Aspen es un servidor Git autoalojable de Reason Machines que escala las escrituras por rama, no por repositorio. Habla Git plano sobre HTTPS y SSH. Los packs van a almacenamiento de objetos compatible con S3; el historial de ramas va a PostgreSQL.

¿Por qué los servidores Git clásicos sufren con los agentes de IA?

Un agente hace push cada pocos minutos, y CI hace fetch después de cada push. Según Reason Machines, un servidor clásico pone en cola todos los pushes a un repositorio juntos. También construye un pack nuevo para cada fetch. El trabajo del servidor crece con los clientes, no con el código nuevo.

OpenAI chocó con este muro y construyó Pando. Redujo la latencia mediana de push casi 5 veces y sirve casi un petabyte al día.

¿Cómo funciona Aspen?

Aspen sigue los pasos de Pando y elimina 2 reclamos que la mayoría de los servidores Git mantienen.

Comparación e intercambio por rama

Cada rama es una cadena de versiones en una sola fila de Postgres. Un push sube su pack y luego mueve la rama con una sola operación de comparación e intercambio. Los pushes a ramas distintas nunca se esperan entre sí. Si 2 pushes compiten en una misma rama, uno gana. El otro recibe el habitual error de Git «fetch first». El costo: las ramas pueden leerse en momentos ligeramente distintos.

Packs almacenados en lugar de packs por cliente

Aspen nunca desempaqueta un push. Verifica el pack, completa las bases faltantes y lo almacena tal cual. Un fetch transmite los packs almacenados que el cliente no tiene, sin recomprimir nada. Las URL firmadas pueden servir packs desde un CDN.

Un push solo ve la rama principal, así que la negociación se mantiene pequeña con un millón de ramas. La compactación en segundo plano combina packs 16 a la vez, en niveles como un árbol de combinación estructurado en registros. Un cliente muy rezagado recibe unas pocas docenas de packs, no miles. Los fetch de CI de profundidad-1 obtienen un pack de punta construido una vez y servido a cada trabajo.

Auto play</button></div> <svg viewBox="0 0 820 250" aria-label="Aspen push and fetch flow"> <defs><marker id="aspA" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0 0L10 5L0 10z" fill="#7cb8f5"/></marker></defs> <g font-family="Inter,sans-serif" font-size="13"> <rect x="20" y="40" width="150" height="60" rx="10" fill="#1d1a12" stroke="#3a3526"/><text x="95" y="66" fill="#f3efe3" text-anchor="middle" font-weight="700">Agente</text><text x="95" y="85" fill="#a59f8c" text-anchor="middle" font-size="11">git push</text> <rect x="20" y="150" width="150" height="60" rx="10" fill="#1d1a12" stroke="#3a3526"/><text x="95" y="176" fill="#f3efe3" text-anchor="middle" font-weight="700">Trabajo de CI</text><text x="95" y="195" fill="#a59f8c" text-anchor="middle" font-size="11">git fetch</text> <rect x="320" y="85" width="170" height="80" rx="12" fill="#1d1a12" stroke="#3690ea" stroke-width="1.5"/><text x="405" y="120" fill="#f3efe3" text-anchor="middle" font-weight="800">Aspen</text><text x="405" y="140" fill="#a59f8c" text-anchor="middle" font-size="11">servidor sin estado</text> <rect x="640" y="30" width="160" height="70" rx="10" fill="#1d1a12" stroke="#3a3526"/><text x="720" y="60" fill="#f3efe3" text-anchor="middle" font-weight="700">Postgres</text><text x="720" y="80" fill="#a59f8c" text-anchor="middle" font-size="11">1 fila por rama</text> <rect x="640" y="150" width="160" height="70" rx="10" fill="#1d1a12" stroke="#3a3526"/><text x="720" y="180" fill="#f3efe3" text-anchor="middle" font-weight="700">Almacenamiento de objetos</text><text x="720" y="200" fill="#a59f8c" text-anchor="middle" font-size="11">packs tal como se enviaron</text> <path id="aspE0" d="M170 70 L320 110" stroke="#3a3526" stroke-width="2" fill="none"/> <path id="aspE1" d="M490 140 L640 180" stroke="#3a3526" stroke-width="2" fill="none"/> <path id="aspE2" d="M490 110 L640 70" stroke="#3a3526" stroke-width="2" fill="none"/> <path id="aspE3" d="M320 140 L170 180" stroke="#3a3526" stroke-width="2" fill="none"/> <circle id="aspPk" r="7" fill="#3690ea"><animateMotion id="aspMo" dur="1.2s" repeatCount="indefinite"><mpath href="#aspE0"/></animateMotion></circle> </g></svg> <p class="cap" id="aspCap"></p> </div> <div class="pane" id="p-race"> <div class="btns"><button class="b" id="aspRun"> Ejecutar 128 escritores</button><button class="b" id="aspReset">Restablecer</button></div> <div class="race"> <div class="rc"><h4>Servidor clásico: una cola por repositorio</h4><div class="dots" id="aspD1"></div><div class="ct" id="aspC1">0 / 128 completados</div></div> <div class="rc"><h4>Aspen: un CAS por rama</h4><div class="dots" id="aspD2"></div><div class="ct" id="aspC2">0 / 128 completados</div></div> </div> <p class="note">Modelo de juguete, no un benchmark. Ámbar = esperando, azul = completado. Refleja la simulación ilustrativa de la publicación de lanzamiento de Reason Machines.</p> </div> <div class="pane" id="p-bench"> <div class="btns"><span class="sub">Pushes por segundo hacia un repositorio, cada uno duradero antes del acuse de recibo</span></div> <div class="bar"><div class="bl"><span>Cursor Origin, S3 Standard (publicado)</span><span>120</span></div><div class="tr"><div class="fl" data-w="21.2" style="background:#6d6650"></div></div></div> <div class="bar"><div class="bl"><span>Cursor Origin, S3 Express One Zone (publicado)</span><span>300+</span></div><div class="tr"><div class="fl" data-w="52.9" style="background:#8a8064"></div></div></div> <div class="bar"><div class="bl"><span>Aspen, S3 Standard (autoinformado)</span><span>567</span></div><div class="tr"><div class="fl" data-w="100" style="background:linear-gradient(90deg,#3690ea,#7cb8f5)"></div></div></div> <div class="grid"><div class="st"><div class="n">208 ms</div><div class="l">push mediano</div></div><div class="st"><div class="n">314 ms</div><div class="l">p99 de push</div></div><div class="st"><div class="n">30 ms</div><div class="l">tiempo mediano hasta ser visible</div></div><div class="st"><div class="n">~4/s</div><div class="l">aterrizajes en main</div></div><div class="st"><div class="n">1.029x</div><div class="l">bytes de profundidad-1 frente a git estándar</div></div><div class="st"><div class="n">5 min</div><div class="l">sostenido, 0 errores</div></div></div> <p class="note">Aspen: 1 servidor de 8 núcleos, S3 Standard, Postgres de 4 núcleos, git.git (~4,500 archivos, 75k commits), URL por rama. Cursor: clúster replicado en su propio monorepo. Las configuraciones difieren; OpenAI no publicó ninguna tasa de push de Pando.</p> </div> <div class="pane" id="p-comp"> <div class="bl"><span>El cliente está rezagado respecto del trunk por</span><span id="aspBeh">2,000 versiones</span></div> <input type="range" id="aspSl" min="1" max="4" step="1" value="3"> <svg viewBox="0 0 820 120" id="aspCS"></svg> <p class="cap" id="aspCC"></p> </div> <div class="pane" id="p-lim"> <div class="lim"> <div class="li"><div class="t"> Pre-alfa, sin versiones publicadas</div><div class="d">Compilar desde el código fuente. Los formatos de almacenamiento pueden cambiar. La prueba de caos de 24 horas se detuvo tras 11.59 horas limpias.</div></div> <div class="li"><div class="t"> Aterrizajes en main ~4/s</div><div class="d">Los aterrizajes separados se ejecutan de uno en uno, limitados por los viajes de ida y vuelta. La tasa de la cola de fusión aún no está medida.</div></div> <div class="li"><div class="t"> Funciones de Git ausentes</div><div class="d">Sin clones parciales, repositorios SHA-256, interfaz web ni claves SSH RSA (solo Ed25519 y ECDSA).</div></div> <div class="li"><div class="t"> El force push requiere -o force</div><div class="d">Como un push solo ve el trunk, --force y --delete necesitan un -o force adicional, un lease o la URL de la rama.</div></div> <div class="li"><div class="t"> Monorepos grandes</div><div class="d">Cada push sigue costando más a medida que crece un repositorio, por lo que los monorepos muy grandes ven tasas menores hoy.</div></div> <div class="li"><div class="t"> Conflicto de soporte de almacenamiento</div><div class="d">La publicación de lanzamiento menciona Azure Blob; el README dice que Azure Blob aún no está soportado y que GCS funciona mediante su API de S3.</div></div> </div> <p class="note">Toca una tarjeta para expandir.</p> </div> <div class="ft"><span>Fuentes: <a href="https://reasonmachines.com/blog/aspen" target="_blank" rel="noopener">publicación de lanzamiento</a> · <a href="https://github.com/reason-machines/aspen" target="_blank" rel="noopener">GitHub</a> · <a href="https://cursor.com/blog/git-at-any-scale" target="_blank" rel="noopener">Cursor</a></span><span class="brand">© Marktechpost</span></div> </div> <script> (function(){ var R=document.getElementById('mtp-aspen'); function post(){try{parent.postMessage({mtpH:R. offsetHeight+40,id:'mtp-aspen'},'*')}catch(e){}} var tabs=R.querySelectorAll('.tab'); tabs.forEach(function(t){t.onclick=function(){tabs.forEach(function(x){x.classList.remove('on')});t.classList.add('on'); R.querySelectorAll('.pane').forEach(function(p){p.classList.remove('on')});R.querySelector('#p-'+t.dataset.t).classList.add('on'); if(t.dataset.t==='bench'){R.querySelectorAll('.fl').forEach(function(f){f.style.width='0';setTimeout(function(){f.style.width=f.dataset.w+'%'},60)})} setTimeout(post,80);setTimeout(post,500)}}); /* flujo */ var caps=['<b>Push.</b> El agente envía un pack. Aspen lo verifica, completa las bases faltantes y lo almacena en almacenamiento de objetos exactamente como llegó.', '<b>Compare-and-swap.</b> Una sola actualización de fila: mover esta rama de A a B solo si todavía apunta a A. Las otras ramas nunca esperan.', '<b>Plan.</b> Al hacer fetch, Aspen lee la fila de la rama y calcula qué packs almacenados cubren lo que falta al cliente.', '<b>Stream.</b> Los packs almacenados se devuelven unidos en un solo pack, o como URLs para una CDN. Nada se recomprime.']; var edges=['aspE0','aspE2','aspE2','aspE3'],live=['aspE0','aspE1']; var sb=R.querySelectorAll('#p-flow .b[data-s]'),cur=0,timer=null; function step(i){cur=i;sb.forEach(function(b){b.classList.toggle('on',+b.dataset.s===i)}); ['aspE0','aspE1','aspE2','aspE3'].forEach(function(e){R.querySelector('#'+e).setAttribute('stroke','#3a3526')}); var on=i===0?['aspE0','aspE1']:i===1?['aspE2']:i===2?['aspE2']:['aspE1','aspE3']; on.forEach(function(e){R.querySelector('#'+e).setAttribute('stroke','#3690ea')}); var mp=R.querySelector('#aspMo mpath');mp.setAttribute('href','#'+(i===0?'aspE0':i===3?'aspE3':'aspE2')); R.querySelector('#aspCap').innerHTML=caps[i]} sb.forEach(function(b){b.onclick=function(){clearInterval(timer);timer=null;R.querySelector('#aspAuto').textContent=' Reproducción automática';step(+b.dataset.s)}}); R.querySelector('#aspAuto'). onclick=function(){if(timer){clearInterval(timer);timer=null;this.textContent=' Reproducción automática';return} this.textContent='❚❚ Pausa';timer=setInterval(function(){step((cur+1)%4)},2200)}; step(0); /* carrera */ var N=128,d1=R.querySelector('#aspD1'),d2=R.querySelector('#aspD2'),rt=null; function build(){d1.innerHTML='';d2.innerHTML='';for(var i=0;i<N;i++){d1.insertAdjacentHTML('beforeend','<div class="dot"></div>');d2.insertAdjacentHTML('beforeend','<div class="dot"></div>')} R.querySelector('#aspC1').textContent='0 / '+N+' completados';R.querySelector('#aspC2').textContent='0 / '+N+' completados'} build(); R.querySelector('#aspReset').onclick=function(){clearInterval(rt);build()}; R.querySelector('#aspRun').onclick=function(){clearInterval(rt);build();var a=d1.children,b=d2.children,k=0,q=0,t=0; for(var i=0;i<N;i++){a[i].className='dot w';b[i].className='dot w'} rt=setInterval(function(){t++; if(q<N){a[q].className='dot d';q++;R.querySelector('#aspC1').textContent=q+' / '+N+' completados'} for(var j=0;j<10&&k<N;j++){b[k].className='dot d';k++}R.querySelector('#aspC2').textContent=k+' / '+N+' completados'; if(q>=N)clearInterval(rt)},45)}; /* compactación */ var lv={1:20,2:200,3:2000,4:20000}; function plan(n){var out=[];[4096,256,16,1].forEach(function(s){while(n>=s){out.push(s);n-=s}});return out} function comp(){var n=lv[R.querySelector('#aspSl').value],ps=plan(n),s=R.querySelector('#aspCS'),x=10,h=''; var tot=ps.reduce(function(a,b){return a+Math.log2(b)+1.5},0); ps.forEach(function(p,i){var w=(Math.log2(p)+1.5)/tot*800;h+='<rect x="'+x+'" y="30" width="'+Math.max(w-3,2)+'" height="50" rx="4" fill="'+(p>=4096?'#7cb8f5':p>=256?'#3690ea':p>=16?'#2f6fb3':'#5a5440')+'"><animate attributeName="opacity" from="0" to="1" dur=".35s" begin="'+(i*0.04)+'s" fill="freeze"/></rect>';x+=w}); h+='<text x="10" y="105" fill="#a59f8c" font-family="Inter" font-size="11">cliente</text><text x="810" y="105" fill="#a59f8c" font-family="Inter" font-size="11" text-anchor="end">trunk</text>'; s.innerHTML=h;R.querySelector('#aspBeh').textContent=n.toLocaleString()+' versiones'; R.querySelector('#aspCC').innerHTML='Plan ilustrativo: <b>'+ps.length+' packs</b> en lugar de '+n.toLocaleString()+'. Los packs se fusionan de 16 en 16 en 4 tamaños (1, 16, 256, 4,096 aquí), y un fetch toma el pack más grande que encaje en cada paso.'} R.querySelector('#aspSl').oninput=comp;comp(); /* límites */ R.querySelectorAll('.li').forEach(function(l){l.onclick=function(){l.classList.toggle('open');setTimeout(post,400)}}); window.addEventListener('load',post);window.addEventListener('resize',post);setTimeout(post,300); })(); </script> </body></html> ">

¿Qué tan rápido es Aspen?

La prueba usó un servidor de 8 núcleos, S3 Standard y un Postgres de 4 núcleos. El objetivo era una copia de git.git, con unos 4,500 archivos y 75,000 commits. Aspen sostuvo 567 pushes por segundo durante 5 minutos sin errores. Cada push llegó a S3 y a Postgres antes de que Git imprimiera «ok.».

  • Latencia mediana de push: 208 ms; percentil 99: 314 ms.
  • Otro cliente vio cada push 30 ms después del acuse de recibo, en la mediana.
  • Tormenta de fetch de profundidad 1: 1.029x los bytes de la versión original git upload-pack en git.git.

Cursor informa hasta 120 pushes por segundo para Origin en S3 Standard. En S3 Express One Zone supera 300. Ese es un clúster replicado en el monorepo de Cursor, por lo que las configuraciones difieren. El README describe las cifras de Aspen como ilustrativas, no como afirmaciones de rendimiento.

¿Cómo se compara Aspen con otros backends de Git a escala de agentes?

CaracterísticaAspenCursor OriginOpenAI PandoGitHub Spokes
DisponibilidadCódigo abierto, autoalojadoPlataforma comercial CursorInterno de OpenAIInterno de GitHub
LicenciaApache 2.0No reveladoNo reveladoNo revelado
Orden de pushPor rama (compare-and-swap)Por repositorio (write-ahead log en S3)Por ramaCommit de tres fases entre réplicas
Almacenamiento de refsPostgreSQL o SQLiteÍndice WAL en S3, sin base de datos relacionalAlmacén de metadatosRepositorios Git en NVMe
Servicio de fetchPacks almacenados, unidos o vía URIsCaché de repositorio Git local en NVMePacks almacenados reutilizadosRéplicas de repositorios Git
Tasa de push publicada567/s, S3 Standard, 1 servidor (autoinformado)120/s S3 Standard; más de 300/s S3 ExpressNo reveladoNo divulgado
Otro resultado publicadop99 de push 314 msEscalado lineal de lectura hasta 100 réplicasLatencia mediana de push reducida casi 5 vecesNo divulgado

¿Cómo despliegas Aspen?

Compilas desde el código fuente con Rust. aspen dev ejecuta todo con SQLite y un directorio local. Los equipos obtienen Docker Compose con PostgreSQL y MinIO, además de un Helm chart. Terraform cubre AWS, Google Cloud, Azure y Hetzner. El modo mirror se sitúa delante de GitHub o GitLab, de modo que puedes probarlo sin migrar.

La demo en vivo es un lienzo de 64 x 64 píxeles donde cada clic es un commit enviado. Según la compañía, un agente Reason construyó Aspen desde el primer commit hasta el lanzamiento público en 4 días. Eso tomó 151 PRs fusionados.

Conclusiones clave

  • Aspen es un servidor Git con licencia Apache 2.0 construido para tráfico de push a escala de agentes.
  • Es una implementación abierta e independiente del diseño Pando de OpenAI.
  • Autoinformado: 567 pushes por segundo en un servidor de 8 núcleos, p99 de 314 ms.
  • Los clientes no necesitan cambios; el git funciona sobre HTTPS y SSH.


Echa un vistazo al repositorio de GitHub y a la publicación de lanzamiento. Además, no dudes en seguirnos en Twitter y no olvides unirte a nuestro SubReddit de 150k+ML y suscribirte a nuestro boletín. ¡Espera! ¿estás en telegram? ahora también puedes unirte a nosotros en telegram.

¿Necesitas asociarte con nosotros para promocionar tu repositorio de GitHub O página de Hugging Face O lanzamiento de producto O webinar, etc.? Conéctate con nosotros

La publicación Reason Machines Open-Sources Aspen, a Git Server Built for AI Agents apareció primero en MarkTechPost.

Fuente original

MarkTechPost

Notas sobre el contenido

La publicación original y los derechos pertenecen a la fuente.

Traducción automática · Consulte el original