Volver al blog

Alternativas a Linear: por que el issue tracking local-first es mas rapido de lo que crees

Linear es rapido. Hay que reconocerlo. Invirtieron fuertemente en rendimiento percibido, y para la mayoria de los equipos, es el mejor issue tracker SaaS disponible. Pero "mejor SaaS" viene con restricciones que algunos desarrolladores no pueden aceptar: tus datos viven en los servidores de alguien mas, tu flujo de trabajo se adapta a sus opiniones, y cada interaccion paga un impuesto de ida y vuelta por la red.

Este post es para desarrolladores que han chocado con esas paredes. Tal vez gestionas flotas de agentes de IA que crean 50 issues por hora. Tal vez trabajas air-gapped u offline-first. Tal vez simplemente no quieres una pantalla de login entre tu y tus issues. Esto es lo que hemos aprendido construyendo Beadbox, un issue tracker de escritorio nativo que mantiene todo local.

Salta a lo que te interesa:

Por que los desarrolladores buscan alternativas a Linear

La respuesta habitual es "Linear tiene demasiadas opiniones." Es cierto pero impreciso. Linear impone ciclos, estructuras de equipo y estados de flujo de trabajo que asumen que eres un equipo de producto lanzando en cadencias de dos semanas. Si ese eres tu, Linear es genial. Si eres un desarrollador solo coordinando agentes de IA, o un equipo de investigacion con patrones de iteracion no estandar, o un grupo de DevOps que necesita issues vinculados a commits de git en lugar de hilos de Slack, las opiniones de Linear se convierten en friccion.

El problema mas profundo es arquitectonico. Linear es un producto SaaS cloud-first. Cada mutacion viaja a sus servidores y de vuelta. Cada consulta depende de su uptime. Tus datos de issues existen en su base de datos, consultables a traves de su API, en sus terminos. Para la mayoria de los equipos, ese es un tradeoff aceptable. Para desarrolladores que se preocupan por la soberania de datos, el acceso offline, o la velocidad bruta de consulta en datasets grandes, es un deal-breaker.

Lo que Beadbox no hace

Antes de entrar en lo que Beadbox hace bien, aqui es donde no es la opcion correcta. Saltarte esta seccion no te ayudara; chocar con estas paredes despues de adoptar una herramienta si te perjudicara.

Sin permisos multi-usuario ni control de acceso. No hay cuentas de usuario, ni roles, ni restricciones de visibilidad por issue. Cualquiera con acceso al filesystem del directorio .beads/ (o al servidor Dolt) puede leer y escribir todo. Si necesitas restringir quien ve que, Beadbox no es para ti hoy.

Colaboracion en tiempo real limitada. Dos personas pueden trabajar en el mismo conjunto de issues, pero el modelo de colaboracion es push/pull (como Git), no cursores en vivo e indicadores de presencia. En modo servidor, Beadbox hace polling cada 3-5 segundos. En modo embebido, los filesystem watches detectan cambios mas rapido (sub-segundo), pero las escrituras concurrentes a la misma base de datos Dolt desde dos procesos pueden fallar. El patron seguro es: un escritor a la vez, o usar modo servidor con Dolt manejando la concurrencia.

Sin integraciones con Slack, GitHub, Figma ni otras herramientas SaaS. El punto de extension es el CLI bd y scripts de shell. Si tu flujo de trabajo depende de "issue cerrado dispara mensaje de Slack," tendras que construir ese pegamento tu mismo.

El techo de escala es real pero distante. Probamos contra datasets de 10K y 20K issues (ver benchmarks abajo). Esos se manejan bien. No hemos hecho pruebas de estres a 100K+ issues. Si eres una organizacion grande generando cientos de miles de issues por ano, este no es territorio probado.

Sin acceso para stakeholders no tecnicos. No hay portal web, ni visor para invitados, ni URL de dashboard compartible. Beadbox es una app de escritorio que lee una base de datos local. Mostrar progreso a un PM que no usa tu maquina significa compartir pantalla o un script bd que genera un reporte.

Como funciona Beadbox (la version de 30 segundos)

Antes de que los benchmarks tengan sentido, aqui esta la arquitectura:

Arquitectura de Beadbox: app Tauri con WebView, servidor WebSocket, CLI bd, base de datos Dolt local y sincronizacion remota opcional

Modo embebido: La base de datos Dolt vive en .beads/ en tu filesystem. Sin proceso de servidor, sin daemon. El CLI bd lee y escribe directamente. Beadbox detecta cambios via fs.watch() con un debounce de 250ms y los transmite por WebSocket a la UI. Este es el camino de configuracion cero.

Modo servidor: Un proceso dolt sql-server corre por separado (local o LAN). El CLI bd se conecta por protocolo MySQL. Beadbox hace polling al servidor cada 3-5 segundos para detectar cambios en lugar de observar el filesystem. Este modo soporta multiples escritores concurrentes.

Cada operacion que la GUI realiza pasa a traves del CLI bd. Beadbox nunca toca la base de datos directamente. Si bd show y Beadbox no coinciden, eso es un bug en Beadbox.

Rendimiento: benchmarks reales en un dataset de 10K issues

El CLI de beads publica benchmarks que puedes reproducir en tu propio hardware. Aqui hay numeros reales de un M2 Pro ejecutando la suite de benchmarks en Go contra una base de datos Dolt de 10,000 issues:

Operacion Tiempo Memoria Dataset
Filtrar trabajo listo (issues desbloqueados) 30ms 16.8 MB 10K issues
Busqueda (todos abiertos, sin filtro) 12.5ms 6.3 MB 10K issues
Crear issue 2.5ms 8.9 KB 10K issues
Actualizar issue (cambio de estado) 18ms 17 KB 10K issues
Deteccion de ciclos (cadena lineal de 5K) 70ms 15 KB 5K deps
Cierre masivo (100 issues) 1.9s 1.2 MB Escrituras secuenciales
Merge de sincronizacion (10 creates + 10 updates) 29ms 198 KB Operacion batch

Estos son benchmarks a nivel de CLI: el tiempo que toma bd para leer o escribir en la base de datos Dolt local. La UI de Beadbox agrega overhead de renderizado encima. Nuestros objetivos de diseno para el stack completo (llamada CLI + render React + propagacion WebSocket) son:

Operacion de UI Objetivo de diseno
Render de arbol de epic (100+ issues) < 500ms
Aplicar/limpiar filtro < 200ms
Cambio de workspace < 1 segundo
Propagacion de actualizacion en tiempo real (embebido) < 2 segundos
Arranque en frio hasta utilizable < 5 segundos

No publicamos benchmarks contra Linear u otros trackers porque no hemos ejecutado comparaciones controladas, y numeros seleccionados a conveniencia no serian honestos. Lo que podemos decir: toda la ruta de datos es local. No hay salto de red entre hacer clic en un filtro y ver los resultados. Si eso te importa depende de tu baseline. Si Linear se siente lo suficientemente rapido para el tamano de tu dataset y tu ubicacion, probablemente lo es. Si has sentido el lag en un backlog de 500 issues desde el Wi-Fi de un hotel de conferencias, conoces el dolor que estos numeros abordan.

Para reproducir: clona beads, ejecuta go test -tags=bench -bench=. -benchmem ./internal/storage/dolt/..., y compara contra tu hardware. Los datasets en cache se guardan en /tmp/beads-bench-cache/.

Profundidad de integracion con Git: mas alla de vincular commits a issues

La mayoria de los issue trackers tratan la integracion con Git como una casilla de verificacion: menciona un ID de issue en un mensaje de commit, y un link aparece en el issue. Eso es util pero superficial.

Beadbox esta construido sobre beads, un issue tracker donde las semanticas de Git son la capa de almacenamiento, no una integracion anadida. Dolt, la base de datos subyacente, implementa el modelo de datos de arbol merkle de Git para datos estructurados. Cada cambio de issue es un commit. Cada commit tiene un padre. Obtienes dolt diff, dolt log y dolt merge sobre tu historial de issues con las mismas semanticas que usas en codigo.

Lo que eso significa en la practica:

Tu historial de issues es auditable. La base de datos misma es un grafo de commits. Puedes hacer diff entre dos puntos en el tiempo y ver exactamente que campos cambiaron en que issues. Esto no es una "funcionalidad de log de auditoria" anadida encima. El formato de almacenamiento es la pista de auditoria.

Branching funciona sobre issues, no solo sobre codigo. Dolt soporta branches nativamente. Puedes hacer branch de tu base de datos de issues para experimentar con una reorganizacion, y luego hacer merge de vuelta o descartarlo.

La sincronizacion es push/pull, no llamadas a APIs. La colaboracion multi-maquina funciona como git push y git pull. Sin tokens de API, sin webhooks, sin flujos OAuth. Apunta tu remote de Dolt a un servidor (o DoltHub) y haz push. La otra maquina hace pull.

Una nota sobre conflictos: Dolt usa three-way merge, igual que Git. Si dos personas editan campos diferentes del mismo issue, el merge se resuelve automaticamente. Si dos personas editan el mismo campo del mismo issue, obtienes un conflicto que requiere resolucion manual a traves del CLI de Dolt (dolt conflicts resolve). Beadbox no tiene una UI de resolucion de conflictos todavia; manejas los conflictos a nivel de dolt. En la practica, los conflictos son raros cuando cada persona (o agente) trabaja en issues distintos, que es el patron tipico. Pero si tu equipo edita frecuentemente los mismos issues de forma concurrente, este es un punto de friccion que deberias conocer. La documentacion de merge de Dolt cubre el flujo de resolucion en detalle.

Renderizado nativo: por que incluimos Node.js dentro de Tauri

Linear corre en una pestana del navegador. Igual Jira, Asana y todos los demas trackers SaaS. Las pestanas del navegador compiten por memoria, son suspendidas por el sistema operativo, y renderizan a traves de un compositor que agrega frames de latencia.

Beadbox corre como una aplicacion de escritorio nativa construida con Tauri. Las apps Tauri son tipicamente diminutas (el runtime de Tauri en si ocupa un solo digito de megabytes) porque usan el WebView nativo del sistema operativo en lugar de incluir Chromium. Nuestro paquete es mas grande que las apps Tauri tipicas con ~160MB, y ese es un tradeoff deliberado que vale la pena explicar.

84MB de eso es un runtime de Node.js embebido. Usamos una arquitectura sidecar: Tauri ejecuta un servidor Next.js como proceso hijo, que maneja el server-side rendering, server actions y la capa WebSocket para actualizaciones en tiempo real. El WebView de Tauri apunta a este servidor local. Elegimos esto sobre un backend puro en Rust porque el ecosistema Next.js nos da React Server Components, server actions y velocidad de iteracion rapida en la capa de UI. El costo es tamano del paquete. Una app Electron equivalente seria 400MB+. Una app pura Rust + Tauri seria menos de 10MB pero habria tomado 3x mas tiempo construir y perderiamos el ecosistema React.

La diferencia practica sobre una pestana del navegador: Beadbox renderiza en un proceso WebView dedicado que no comparte memoria con tus otras 47 pestanas del navegador. Expandir un arbol de epic con 100+ issues anidados, aplicar filtros a traves de un backlog completo, cambiar entre workspaces: estas operaciones se sienten cualitativamente diferentes cuando el renderizador no compite por recursos.

Extendiendo con el CLI, no con una API REST

Linear tiene una API GraphQL. Esta bien disenada. Pero extender Linear significa escribir codigo que habla con sus servidores, se autentica con sus tokens y maneja sus rate limits.

Beadbox toma un enfoque diferente: el CLI bd es la API. Cada operacion que la GUI realiza pasa por bd, la misma herramienta de linea de comandos que usarias en tu terminal.

Aqui hay tres flujos de trabajo que puedes copiar y pegar hoy:

Actualizar prioridades masivamente para una ronda de triaje:

# Poner todos los bugs abiertos en prioridad 1 (critica)
bd list --status=open --type=bug --json | \
  jq -r '.[].id' | \
  xargs -I{} bd update {} --priority=1

Generar un resumen de estado diario:

# Que cambio en las ultimas 24 horas?
echo "=== Cerrados hoy ==="
bd list --status=closed --json | \
  jq -r '.[] | select(.updated > (now - 86400 | todate)) | "\(.id) \(.title)"'

echo "=== Actualmente bloqueados ==="
bd blocked --json | \
  jq -r '.[] | "\(.id) \(.title) (bloqueado por: \(.blocked_by | join(", ")))"'

echo "=== Listos para trabajar ==="
bd ready --json | jq -r '.[] | "\(.id) [P\(.priority)] \(.title)"'

Un agente de IA crea y reclama trabajo:

# El agente descubre un bug, lo reporta y lo reclama
ISSUE_ID=$(bd create \
  --title "Fix race condition in auth middleware" \
  --type bug \
  --priority 1 \
  --json | jq -r '.id')

bd update "$ISSUE_ID" --status=in_progress --assignee=agent-3

# ... el agente hace el trabajo ...

bd update "$ISSUE_ID" --status=closed
bd comments add "$ISSUE_ID" --author agent-3 \
  "Fixed in commit abc1234. Root cause: mutex not held during token refresh."

Si estas ejecutando agentes de IA para programar (Claude Code, Cursor, Copilot Workspace), ya saben como ejecutar comandos CLI. Sin libreria cliente de API, sin danza de autenticacion. Solo Unix pipes y scripts de shell.

Prueba Beadbox para ver estos flujos de trabajo visualizados en tiempo real mientras los agentes los ejecutan.

Offline-first no es una funcionalidad, es una arquitectura

Algunos trackers en la nube ofrecen un "modo offline" que almacena datos recientes en cache y sincroniza cuando te reconectas. Eso es una funcionalidad anadida a una arquitectura fundamentalmente online. Los modos de fallo son predecibles: cache obsoleta, conflictos de sincronizacion, operaciones que se encolan silenciosamente y fallan despues.

Beadbox funciona offline porque nunca estuvo online en primer lugar. En modo embebido, toda tu base de datos de issues es un directorio en tu filesystem. Sin proceso de servidor. Sin daemon. Sin socket de red. El CLI bd lee y escribe en ese directorio. Beadbox lo observa con fs.watch() y renderiza lo que encuentra.

No hay nada que sincronizar porque no hay nada remoto. Si despues eliges colaborar, el push/pull de Dolt te da sincronizacion explicita y visible. Pero el default es local. El default es tuyo.

Que hay de la seguridad? Si estas evaluando Beadbox para entornos air-gapped o sensibles, aqui esta la postura concreta:

  • Cifrado en reposo: Beadbox no cifra el directorio .beads/ por si mismo. Se apoya en el cifrado a nivel de sistema operativo (FileVault en macOS, LUKS en Linux, BitLocker en Windows). Si tu modelo de amenazas requiere cifrado por base de datos, este es un vacio.
  • Backups: Tu directorio .beads/ es un directorio regular. cp -r, rsync, Time Machine, o dolt push a un remoto, todos funcionan. El historial de commits de Dolt tambien significa que los cambios accidentales pueden revertirse con dolt reset.
  • Que sale de la maquina: En modo embebido, nada. Cero llamadas de red. En la app de escritorio, existen dos conexiones salientes opcionales: la API de GitHub para verificar actualizaciones de Beadbox (se puede desactivar en configuracion), y analiticas PostHog si optas por habilitarlas (desactivadas por defecto, no se recopila PII). Ninguna transmite datos de issues.

Para entornos air-gapped, proyectos clasificados, o desarrolladores que trabajan en aviones y trenes, esto no es un nice-to-have. Es la unica arquitectura que funciona.

Eligiendo la herramienta correcta para tu equipo

Ninguna herramienta es universalmente correcta. Aqui hay un desglose honesto:

Elige Linear si:

  • Tu equipo tiene 10+ personas y necesita gestion de proyectos centralizada
  • Dependes de integraciones con Slack/GitHub/Figma
  • Stakeholders no tecnicos necesitan acceso a tu issue tracker
  • Quieres infraestructura gestionada con cero overhead operacional
  • Eres un equipo de producto lanzando en ciclos regulares

Elige Beadbox si:

  • Valoras la soberania de datos (los issues nunca salen de tu maquina)
  • Trabajas offline regularmente o en entornos de red restringidos
  • Gestionas agentes de IA que necesitan leer y escribir issues programaticamente
  • Quieres historial de issues Git-native (branch, diff, merge tus issues)
  • Prefieres flujos de trabajo CLI-first con un companero visual cuando lo necesitas
  • Eres un desarrollador solo o equipo pequeno (1-10) que no necesita funcionalidades enterprise

Sigue con tu herramienta actual si:

  • El costo de cambio supera la friccion que estas experimentando
  • Tu equipo ha invertido en integraciones que dependen de la API de tu tracker actual
  • Tu flujo de trabajo ya encaja con las opiniones de tu herramienta

Migrando desde Linear (u otros trackers)

Seamos directos: no hay una herramienta automatizada de migracion de Linear a Beadbox hoy. Sin wizard de importacion CSV, sin puente de API, sin UI de mapeo de estados.

Si estas empezando de cero, perfecto. bd init, empieza a crear issues, y Beadbox los ve inmediatamente. Cero friccion.

Si tienes un proyecto existente en Linear que quieres traer, el camino viable ahora mismo es con scripts: exporta desde la API de Linear (soportan exportacion CSV y API), transforma los datos, y usa bd create en un loop para recrear los issues. Perderas metadatos especificos de Linear (ciclos, vistas de proyecto, timers de SLA) pero preservaras titulos, descripciones, prioridades y estados. Un script de migracion es un proyecto de fin de semana, no una integracion de un trimestre.

Sabemos que esto no es suficiente para equipos con miles de issues y anos de historial. Construir un pipeline de importacion adecuado esta en nuestro roadmap pero aun no esta listo. Si la friccion de migracion es tu preocupacion principal, espera hasta que lo hayamos construido, o evalua si empezar de cero es aceptable para tu caso de uso.

Para empezar

Beadbox es gratis durante la beta. Instalalo con Homebrew:

brew tap beadbox/cask && brew install --cask beadbox

Si ya usas beads, Beadbox detecta tus workspaces .beads/ existentes automaticamente. Abre la app y tus issues estan ahi. Sin paso de importacion. Sin creacion de cuenta.

Si eres nuevo con beads, Beadbox te guia para inicializar tu primer workspace. Estaras viendo tus issues en menos de 60 segundos.

Descarga Beadbox o revisa beads para ver si el issue tracking local-first se ajusta a tu flujo de trabajo.