LUCIANO CARRIZO
Todos los proyectos
ArchivadoPrivado

openlucho

Una capa de persistencia y continuidad sobre Claude Code: observa las sesiones que Claude ya escribe en disco, las persiste en SQLite y arma una memoria viva en markdown que cita los eventos reales de los que sale cada dato. Nació como otra cosa — un orquestador para abaratar subagentes — hasta que un spike propio midió que rutear costaba 3.3× más y el producto cambió de rumbo. Archivado.

RustTypeScriptTauriSQLiteReact
Qué es

Observar, persistir, continuar

openlucho es una capa de persistencia, continuidad y progreso observable sobre Claude Code. Claude ya escribe cada sesión en disco, como transcripts .jsonl bajo ~/.claude/projects/. La app los observa sin invadirlos — no se mete en el medio, no envuelve al agente, no depende de la API ni del SDK: el runtime es puro disco y observación. Normaliza los eventos, los persiste en SQLite y los presenta en una app de escritorio hecha con Tauri.

La cadena que ordena todo el proyecto es esa: observar → persistir → continuar. La fricción que ataca es la de siempre cuando trabajás con un agente sesión tras sesión: lo que pasó en la sesión anterior queda en un archivo que nadie lee, y arrancar de nuevo significa volver a contar el contexto entero. El tercer eslabón —continuar— es el que da sentido a los otros dos.

La app (apps/visualizador) tiene seis vistas. La que más define el tono es “Agéntica”: renderiza la conversación con la estética de Claude Code —tools colapsables, diffs en rojo y verde, jerarquía de burbujas— leyendo el .jsonl de forma efímera y lazy, sin duplicar el contenido en el store. La observación no se paga dos veces.

El pivote

Planteé un orquestador barato y mi propio spike lo mató

El proyecto no empezó siendo esto. La idea original era un orquestador: un mecanismo que ruteara trabajo entre sesiones separadas de Claude Code para esquivar el costo de los subagentes nativos. La hipótesis era económica, no técnica — que mover el trabajo a sesiones propias salía más barato que delegarlo por el camino oficial.

Antes de construir el producto sobre esa hipótesis, la medí. Un spike —el A1, documentado en docs/vision.md— la falsificó en la práctica. El razonamiento que apareció al medir es el que no había visto al plantearla: los subagentes nativos de Claude Code ya aíslan el contexto del orquestador. Corren en su propia ventana y solo devuelven el resumen; el costo que yo creía estar pagando de más ya estaba resuelto del otro lado. Rutear vía MCP a sesiones separadas no ahorra nada. Cuesta 3.3× más a nivel sistema.

Ese número es el que decidió el proyecto. No hubo forma de rescatar la idea original: si el ahorro era la razón de existir del orquestador y el ahorro no existe, lo que queda no es una versión más chica de lo mismo — es otro producto. El rumbo cambió hacia lo que sí quedaba en pie de todo lo construido: la observabilidad y la continuidad. Persistir lo que pasa, hacerlo legible, y poder retomarlo.

Lo que perdí con esa decisión fue el gancho comercial más vendible que tenía el proyecto —“gastás menos”— a cambio de uno mucho más difícil de explicar en una frase. Lo que gané fue que el spike, además de matar una hipótesis, dejó libre el camino hacia la pieza más original de todo el repo, que es la que sigue.

La memoria viva

Una memoria que cita sus fuentes en vez de sintetizar

El crate crates/memoria es el backbone del proyecto después del pivote, y la parte de la que estoy más conforme. Escribe una memoria viva en markdown transparente dentro del propio proyecto observado, en <proyecto>/.openlucho/memoria/. Markdown, en el repo, legible sin la app: la memoria no es un blob binario que solo entiende la herramienta que lo escribió.

La captura es graded, en tres niveles: auto (lo que se extrae solo de los eventos), semi y curada (lo que pasó por mi criterio). No todo lo que se recuerda vale lo mismo, y el nivel viaja con el dato en vez de quedar en la cabeza de quien lo escribió. Encima de eso hay un índice FTS5 propio, automático, sobre SQLite: buscar en la memoria es una consulta, no un grep a mano sobre markdown.

Pero lo que hace distinto al proyecto es el comando rotar. Cuando la memoria crece y hay que comprimirla para volver a inyectarla en una sesión nueva, la salida no es un resumen sintetizado por un modelo: es un prompt-resumen pegable donde cada hecho cita los eventos genuinos de los que sale. Ese es el mecanismo anti-opacidad, y es deliberadamente lo contrario de lo que hace un resumen automático. Un resumen sintetizado es cómodo y opaco: no podés auditar de dónde salió cada afirmación, y cuando el modelo rellena un hueco, rellena en silencio. Una memoria que cita se puede verificar hecho por hecho.

Ese diseño no se quedó en intención: lo validé con otro spike, el A4 — un crate desechable, member del workspace, escrito para medir y para tirar. Midió el recall de la rotación asistida sobre 6 sesiones reales y 3.926 eventos, usando el ORCHESTRATOR.md del propio repo como gold standard. Los resultados:

ModoRecallHechos inventados
Determinístico (sin LLM)~40 %0 %
Asistido (agente citando eventos)~90 %0 %

La columna que importa es la segunda. El salto de ~40 % a ~90 % de recall dice que el agente aporta —lo determinístico solo no alcanza—, pero el 0 % de hechos inventados es el que valida la tesis: obligar a citar el evento de origen no es una decoración de auditoría, es lo que hace que asistir con un modelo no degrade en alucinar. Y también marca el techo honesto del mecanismo: ~90 % no es 100 %. Hay hechos que la rotación asistida no recupera, y eso queda dicho, no promediado.

Completa la pieza un daemon, memoria capturar, que ingesta en vivo y regenera el estado.md a medida que la sesión avanza.

La arquitectura

Rust en workspace, Clean Architecture por módulo

El backend es Rust (edición 2021), organizado como workspace multi-crate con Clean Architecture aplicada por módulo: crates/capturador (observar) y crates/memoria (persistir y continuar), cada uno con sus capas domainapplicationinfrastructure y el dominio sin dependencias externas. Separarlos así no fue simetría decorativa: el capturador sobrevivió intacto al pivote justamente porque no sabía nada de para qué se iban a usar los eventos que normalizaba.

El capturador expone una CLI propia —ingest, sessions, stats, watch— y usa notify como file watcher cross-platform para seguir los .jsonl en vivo. La persistencia va a SQLite vía rusqlite con la feature bundled, que es también donde vive el índice FTS5 de la memoria. Tauri 2 es el shell de escritorio, con React 19 + TypeScript + Vite adentro; la app queda excluida del workspace de Cargo a propósito, porque necesita el dist del frontend para compilar y se buildea aparte.

Del lado de la disciplina hay dos cosas que no son código y que igual definen el repo: un ORCHESTRATOR.md de handoff vivo entre sesiones —estado, decisiones, gotchas, roadmap— y un docs/archive/ donde las decisiones descartadas se mueven con git mv en vez de borrarse. Guardar el porqué, no solo el qué. 61 commits, un solo autor.

El cierre

Por qué lo dejé, y qué salió de dejarlo

El repo no tiene actividad desde el 2 de julio de 2026, y por eso está publicado acá como archivado y no como “en proceso”. No lo dejé porque fallara: el pivote se resolvió, la memoria viva funciona y está medida. Lo dejé porque en el camino apareció una pregunta más grande que el proyecto.

El último movimiento del repo fue un PR de investigación —“investigación de opcode como base del workspace de agentes”— que sigue abierto hasta hoy. Ese mismo 2 de julio arranca opcode-lucho. No es coincidencia de fechas: es literalmente lo que salió de investigar esto. Evaluar si convenía construir mi propia GUI desde cero o partir de una que ya existía terminó en un fork propio, y ahí se fue el tiempo que este proyecto no volvió a tener.

Lo dejo publicado igual, y archivado sin maquillaje, porque el valor del caso no está en que haya llegado a producción — no llegó. Está en las dos decisiones que quedaron medidas: una hipótesis de producto que no sobrevivió a su propio spike, y un mecanismo de memoria que prefiere citar antes que sintetizar.

Siguiente paso

El caso muestra el código. Hablemos de lo que sigue.

openlucho está documentado end-to-end: arquitectura, decisiones y lo que quedó pendiente. Si tenés preguntas sobre el enfoque, escribime.

Hablemos

o directamente → LuchoC.dev@gmail.com