Una GUI de escritorio para Claude Code, sobre un codebase que no escribí
opcode-lucho es una aplicación de escritorio (Tauri 2 + Rust en el backend, React 18 + TypeScript en el
frontend) que le da interfaz gráfica a Claude Code: gestión de proyectos y sesiones, agentes propios,
servidores MCP, checkpoints y un dashboard de consumo de tokens. No es un producto original mío ni un
servicio web, y no está afiliado a Anthropic.
Es un fork de winfunc/opcode, licenciado AGPL-3.0. GitHub no lo
marca como fork técnico (el repo es independiente, con el historial upstream importado), así que la única
forma de que se sepa es decirlo yo: de los 522 commits del repo, 321 son míos (250 sin contar merges,
a lo largo de 10 días de trabajo, 2026-07-02 a 2026-07-11). El resto — el concepto de la app, el andamiaje
Tauri, los agentes de Claude Code, MCP, checkpoints y buena parte de los componentes — vino del upstream.
Cargo.toml sigue acreditando a sus autores originales; no toqué esa línea.

Lo que heredé, tal cual estaba
El fork arranca en el commit 70c16d8 (2025-10-13, el último del upstream antes de mi primer commit
propio). El propio README lo dice de frente, con un aviso [!IMPORTANT]:
“This is a fork.
opcode-luchois a personal fork ofwinfunc/opcode(originally by Asterisk), licensed under AGPL-3.0… do not report issues about this fork upstream.”
Heredé el concepto entero de la app y su andamiaje: Tauri 2 + React, los agentes de Claude Code, MCP,
checkpoints, el servidor web (web_server.rs) y la mayoría de src/components/. También heredé la
licencia AGPL-3.0 y el crédito de los autores upstream con más volumen (Vivek R, Mufeed VH, Kiran Johns),
que dejé intacto en Cargo.toml.
Lo que no heredé fue nada del cómo se mantiene: ni CI en verde, ni documentación propia, ni una navegación que yo entendiera de memoria. Eso es lo que sigue.
Navegación y detalle de proyecto, desde cero
Sidebar y navegación
LeftSidebar.tsx, archivo nuevo de +1.067 líneas: tab strip por proyecto, titlebar propio estilo Windows y una vista Home que no existía.
Detalle de proyecto
ProjectDetail.tsx (nuevo, +502), ProjectFileTree.tsx, SessionAside.tsx y SessionPickerDialog.tsx: la vista que faltaba para entrar a un proyecto y ver sus sesiones sin perderse.
Plantillas y backups de CLAUDE.md
claude_templates.rs, claude_backups.rs y claude_fs.rs en el backend, más ClaudeTemplatesView.tsx (+394) en el frontend.
Application settings
app_settings.rs + ApplicationSettings.tsx, nuevos los dos, con settings que cablean comportamiento real de la app, no un formulario decorativo.
Nada de esto estaba en el upstream. Cada pieza entró por su propio PR (72 en total, todo el trabajo pasó
por revisión antes de mergear a master).
16 documentos para poder tocar código ajeno
Antes de reescribir una vista tenía que entender cómo estaba armada la que ya existía, y el upstream no
traía esa documentación. Terminé escribiendo docs/views/: 16 documentos, uno por vista, en inglés,
escritos después de construir la feature correspondiente — no como planificación, sino como el mapa que
me hubiera ahorrado tiempo si hubiera existido antes.
navigation-model.md es el que más uso: describe cómo se relacionan el sidebar, el tab manager y el
titlebar, que es exactamente la parte que reescribí en la zona anterior. Documentar un codebase ajeno
terminó siendo tan parte del trabajo como escribir el código nuevo.
Reescribir el backend de métricas, no solo la vista
El dashboard de consumo de tokens venía del upstream, pero terminé reescribiéndolo de punta a punta, y es
la pieza en la que más tiempo invertí de las cuatro. src-tauri/src/commands/usage.rs (+1.383 / −329
líneas) es el archivo más tocado de todo el repo — más que cualquiera de la navegación. Del lado del
frontend, una carpeta nueva entera, src/components/usage-detail/ (17 archivos), más
dashboard/DashboardBento.tsx y la lógica de agregación extraída a lib/usageAggregation.ts (+349).

Lo que se ve en esa captura es el resultado, no el punto de partida. El upstream traía una vista de uso con métricas sueltas; lo que reescribí fue tanto el cómo se calculan (el backend en Rust, que es donde cayó el grueso del diff) como el cómo se leen: un bento de 11 métricas de un vistazo, un panel de filtros por modelo, y un gráfico de actividad temporal que cruza tres métricas — costo, tokens, sesiones — con tres formas de visualizarlas — barras, velas, línea — en vez de un solo gráfico fijo.
El upstream describe la mejora como “carga mucho más rápida en historiales grandes”. No tengo un
antes/después medido de esa afirmación, así que no invento un número acá — pero coincide con por qué me
metí a tocar el backend en primer lugar: la vista de uso original no aguantaba bien un historial de
sesiones grande, y la reescritura de usage.rs fue la respuesta a eso, no un capricho de diseño.
Separar la lógica de agregación en un módulo puro (usageAggregation.ts) en vez de dejarla mezclada en
los componentes fue deliberado: es el mismo criterio que apliqué en los otros 12 módulos nuevos de
src/lib/ — la lógica derivada del frontend vive aparte de la vista que la consume.
Heredar código también es heredar su infraestructura
La CI heredada nunca había pasado en verde
El workflow pr-check.yml fallaba en TODOS los PRs, por dos causas apiladas y ninguna del código: primero, nunca instalaba las dependencias de sistema de Tauri en ubuntu-latest ("Package glib-2.0 was not found"), aunque la lista correcta ya existía en otro workflow del mismo repo. Arreglado eso, seguía fallando porque bun run check corre tsc y cargo check, y cargo check necesita dist/index.html (vía include_str! en web_server.rs) — algo que tsc nunca genera, porque solo tipa. Había que compilar el frontend antes de correr cargo check. Hoy pr-check pasa en 7m51s.
Por qué no hay binarios distribuibles
Hay un tag v0.3.1 sobre master, el primer release propio del fork, pero no hay ningún GitHub Release publicado. El workflow de macOS pide 7 secrets de firma y notarización de la cuenta de Apple Developer del proyecto original, que no se heredan al forkear — sin ellos, y sin firma, macOS Gatekeeper bloquea la app. Es una restricción externa, no una carencia técnica.
También protegí master y dev con rulesets sin bypass para nadie, ni para mí como admin: exigen PR y
el check bun run check en verde, y bloquean el force-push. Un dato que aprendí en el camino: los
rulesets de protección no existen en GitHub Free para repos privados — el orden quedó forzado a
público primero, protección después, y así lo hice.
El proyecto está cerrado como versión, no distribuido: lo que siga desde acá van a ser fixes puntuales, no una vuelta a trabajarlo a este ritmo.
