ULTRON Control Center
by SkiTemplar
README.md
<h1 align="center">ULTRON Control Center</h1>
<p align="center">
<em>Una capa de memoria gobernada, enrutado multi-LLM y orquestacion de
skills/agentes para <a href="https://claude.com/claude-code">Claude Code</a>.</em>
</p>
<p align="center">
<img alt="version" src="https://img.shields.io/badge/version-15.8.0-555">
<img alt="stack" src="https://img.shields.io/badge/Tauri_2-%2B_React_19-555">
<img alt="backend" src="https://img.shields.io/badge/backend-Rust_2021-555">
<img alt="memoria" src="https://img.shields.io/badge/memoria-SQLite_%2B_Qdrant-555">
<img alt="plataforma" src="https://img.shields.io/badge/plataforma-Windows_11-555">
<img alt="licencia" src="https://img.shields.io/badge/licencia-MIT-555">
</p>
Cockpit personal de escritorio (Tauri 2 + React 19) construido sobre la CLI de
Claude Code. Vive bajo `~/.ultron/` y reune tres piezas: **memoria gobernada**,
**AI Router** y un **orquestador de skills/agentes**. No reemplaza a Claude
Code: lo envuelve con estado persistente, inspeccionable y versionable.
> Repositorio MIT de un solo mantenedor, pensado para publicarse (hoy la
> visibilidad la decide el mantenedor: si puedes leer esto en GitHub, ya es
> publico). No es un producto comercial ni un SaaS. Esta documentacion
> describe el sistema tal y como esta en el disco; no contiene secretos ni
> datos personales (la informacion personal vive solo en ficheros locales
> fuera de control de versiones).
- **Version**: 15.8.0 (`control-center/package.json`, `Cargo.toml`, `tauri.conf.json`)
- **Plataforma**: Windows 11 (objetivo principal); Linux x86_64 compila pero el
flujo end-to-end no esta verificado por el autor.
- **Licencia**: MIT (ver [`LICENSE`](LICENSE)).
---
## Quickstart
**Sistema completo** (app + skills + hooks + memoria semantica) — el camino
recomendado; es idempotente y pregunta antes de tocar nada:
```powershell
git clone https://github.com/SkiTemplar/ultron.git $env:USERPROFILE\.ultron
cd $env:USERPROFILE\.ultron
powershell -ExecutionPolicy Bypass -File .\install.ps1 # Linux: ./install.sh
```
**Instalacion por componentes** (sin wizard, determinista; `-DryRun` lista el
plan sin tocar nada):
```powershell
.\install.ps1 -Core # app + memoria + hooks (el set por defecto)
.\install.ps1 -All # core + skills + tones + agents
.\install.ps1 -Skills -Tones # a la carta
.\install.ps1 -Core -DryRun # solo listar que haria
# Linux: ./install.sh --core | --all | --skills | --tones | --agents | --dry-run
```
**Solo la app de escritorio** (sin skills/hooks/sidecar de memoria):
```bash
git clone https://github.com/SkiTemplar/ultron.git ~/.ultron && cd ~/.ultron/control-center
cp ../.env.example ../.env # opcional: claves de proveedores LLM (todas vacias por defecto)
npm install
npm run build:app # = kill-app + tauri build -> ejecutable de escritorio
```
Guia completa (bootstrap one-liner desde release, flags, troubleshooting):
[`INSTALL.md`](INSTALL.md).
Qdrant es opcional (el recall degrada a sparse-only sin el); ver la seccion
Qdrant de [`docs/INSTALL-ADVANCED.md`](docs/INSTALL-ADVANCED.md).
Las rutas per-maquina se documentan en
[`config/paths.example.toml`](config/paths.example.toml).
## Caracteristicas
- **Memoria gobernada** — `brain.db` (SQLite) como unica fuente de verdad; todo
cambio pasa por un unico servicio que anexa un evento de auditoria.
- **Recall hibrido** — denso (E5 1024d / Qdrant) + sparse (FTS5/BM25) fusionados
con Reciprocal Rank Fusion; degrada a sparse-only sin Qdrant.
- **Inbox de candidatos** — las capturas automaticas proponen, el humano aprueba;
nunca se auto-escribe memoria activa.
- **Redaccion + dedupe** en el write-path — secretos/PII fuera, duplicados por
`content_hash` fuera, antes de persistir o embeber.
- **AI Router** — cadena primario -> fallbacks por zona, deteccion de claves y
telemetria de uso/ahorro; routing directo en Rust (sin sidecar LiteLLM).
- **Orquestador por reglas** — mapea prompt -> intent -> workflow -> agentes ->
memorias; reserva el modelo grande solo para la cola ambigua.
- **Tonos / personalidades** — deteccion determinista del tono del chat
(senales lexicas + peticion explicita) dentro del orchestrate; los tonos se
editan en Library -> Tones. La config real (`~/.ultron/personality.json`) es
local y gitignored; el repo publica solo los seeds compilados
(`orchestrator/personality.rs`). El tono viste unicamente la conversacion:
nunca commits, docs ni artefactos.
---
## Que es
ULTRON Control Center no reemplaza a Claude Code: lo envuelve. Le da memoria
persistente y gobernada, enruta peticiones a varios proveedores LLM segun coste
y disponibilidad, y detecta automaticamente que skill/agente especialista
conviene para un prompt. Todo el estado vive en ficheros locales (SQLite +
JSON + markdown) que puedes inspeccionar, versionar y editar a mano.
| Pilar | Que hace |
|---|---|
| **Memoria gobernada** | `~/.ultron/brain.db` (SQLite) es la **unica fuente de verdad**. Toda escritura pasa por un unico servicio que ademas registra un evento de auditoria. Las capturas automaticas nunca escriben memoria activa directamente: proponen candidatos a un inbox que el humano aprueba o rechaza. |
| **Recall hibrido** | Fusion de dos fuentes con Reciprocal Rank Fusion (RRF): **denso** (vectores E5 1024d en Qdrant) + **sparse** (FTS5/BM25 sobre `brain.db`). Degrada a solo-sparse si Qdrant/E5 no estan disponibles. |
| **AI Router** | Catalogo de proveedores + zonas con cadena primario -> fallbacks, deteccion de claves, telemetria de uso/ahorro. Sin sidecar LiteLLM: routing directo en Rust. |
| **Orquestador** | Mapea un prompt (posiblemente vago) a intent -> workflow -> agentes a delegar -> memorias relevantes -> restricciones, mediante reglas (no usa el modelo grande para lo que resuelven reglas/triggers). |
---
## Arquitectura del backend (real)
El backend Rust vive en `control-center/src-tauri/src/`. El modulo central de
memoria esta en `control-center/src-tauri/src/memory/`.
### Memoria: SQLite como fuente de verdad
- **`~/.ultron/brain.db`** (SQLite, modo WAL) es la **SoT canonica**. El esquema
canonico vive en `memory/schema_v3.rs` (memoria) + `memory/schema_v4.rs`
(migracion historica v4: tablas `edges` / `unresolved_refs`, hoy inertes — el
grafo de codigo lo provee el MCP CodeGraph externo) /
`memory/migrations.rs`, con modelos en `memory/model.rs` (`MemoryItem`,
`MemoryCandidate`, `MemoryEvent`, y los enums de gobernanza `Status`, `Scope`,
`Sensitivity`, `Source`, etc.).
- **`MemoryService`** (`memory/service.rs`) es el **unico escritor persistente**.
Invariante de gobernanza: toda mutacion pasa por aqui y **anexa un
`MemoryEvent`** de auditoria. Hooks y agentes nunca escriben `memory_items`
directamente; solo proponen `MemoryCandidate`s que un humano (o una politica
de auto-aprobacion) promueve.
- En el camino de escritura se aplican guardas: **redaccion de secretos/PII**
(`memory/redaction.rs`) antes de persistir o embeber, **dedupe** exacto por
`content_hash` (`memory/texthash.rs`) y dedupe lexico por FTS.
### Qdrant: indice derivado (no fuente de verdad)
- La coleccion **`ultron_memory`** (Qdrant) indexa los items ACTIVE con
**MultilingualE5Large, 1024 dimensiones** (`memory/qdrant_index.rs`). Es un
**indice derivado**: se puede reconstruir en cualquier momento con
`reindex_all` y `brain.db` sigue siendo la verdad.
- Tras cada escritura aprobada/editada/restaurada, `sync_index` mantiene Qdrant
en paso con la SoT (best-effort; cualquier deriva es detectable/reparable via
`reconcile`).
- La coleccion antigua `ultron_sessions` (384d BGE) esta retirada; Qdrant aqui
es siempre un indice, nunca la verdad.
### Recall hibrido denso + sparse con RRF
- El comando unico `recall` (`commands/memory/recall_unified.rs`) fusiona con
**Reciprocal Rank Fusion** (`RRF_K = 60`):
- **DENSO**: vectores E5 en `ultron_memory` (Qdrant).
- **SPARSE**: FTS5/BM25 sobre `memory_items` (solo `status=active`).
- Devuelve un *context pack* compacto de resumenes bajo presupuesto de tokens
(`TOKEN_BUDGET = 1500`), con trazas de *por que esta memoria* (rangos por
fuente, scores, descartes) para el Retrieval Inspector.
- El antiguo `recall_hybrid` (union de scores constantes, multi-store) fue
**eliminado el 2026-06-28** sin callers vivos: el unico camino de recall es
el comando unificado `recall` con RRF. Las patas multi-store **ECC**, **KG**
y **Mem0** estan **retiradas** (Mem0 esta muerto por politica; no
reintroducir): hoy las unicas fuentes vivas son Qdrant (denso) +
SQLite/FTS5 (sparse).
### Captura automatica via Stop hook
- En `Stop`, el hook pasa el transcript de la sesion a
`memory/capture.rs::capture_session`. Este:
1. pide a un LLM (via `ai_router::route`, zona `chat`) extraer unos pocos
hechos/decisiones durables;
2. convierte cada hecho en un `MemoryCandidate` (pasando por redaccion +
dedupe) y lo deja en el **inbox gobernado** para aprobacion humana — nunca
se auto-promueve a activo.
- Fail-safe: si el router no tiene proveedor utilizable, degrada a una
heuristica local barata para que el Stop hook nunca falle.
- El inbox se gestiona desde `commands/memory/inbox.rs`
(`memory_inbox_list`, `approve_candidate`, `reject_candidate`).
### AI Router: zonas, proveedores, fallback y telemetria
- Backend en el modulo `ai_router/` (mod.rs + exec.rs + providers/ + seed.rs + store.rs). Estado en tres JSON bajo
`~/.ultron/cockpit/ai-router/`: `providers.json` (catalogo), `zones.json`
(zonas con `primary` + `fallbacks`), `metrics.json` (contadores + ahorro).
- `route(zone, prompt)` recorre la cadena **primario -> fallbacks**, salta
proveedores sin clave API utilizable, registra latencia/tokens/ahorro en la
telemetria y devuelve `Result<String, String>` (errores verbatim, nunca panic,
cap de 10s).
- Wrappers por proveedor: **anthropic** (claude-haiku), **codex** (OpenAI-compat),
**gemini**, **groq**, **ollama** (local, sin clave), **deepseek**. Los health
checks usan sondas baratas y no gastan tokens; las invocaciones de test si.
- Zonas por defecto incluyen `chat`, `code-edit`, `code-review`, `research-web`,
`code-fast-local`, entre otras.
### Orquestador: deteccion automatica de skills/agentes
- El modulo `orchestrator/` (rules.rs + ranking.rs + orchestrate.rs) mapea `prompt -> intent -> workflow -> agentes a delegar ->
memorias -> restricciones`. La clasificacion de intent es **basada en reglas**
(bilingue es/en); el modelo grande se reserva para la cola ambigua.
- Reutiliza (no duplica): el catalogo de agentes (`memory/catalog.rs`), el recall
unificado y los workflows integrados (`agent_orchestration.rs`). Nunca escribe
memoria persistente y delega a agentes reales en `~/.claude/agents`
(los "ghost agents" inexistentes en disco se sanean).
### Grafo de codigo: MCP CodeGraph (externo)
- El grafo de codigo (que simbolos existen, quien llama a quien, analisis de
impacto) lo provee **CodeGraph** (`@colbymchenry/codegraph`, MIT), instalado
como **servidor MCP** y consultado por los agentes via `codegraph_explore` /
`codegraph_callers` / `codegraph_impact`. Indexa el repo con tree-sitter (AST)
en `.codegraph/` (SQLite local, incremental) — 20+ lenguajes.
- El casero v4 anterior (regex + tablas `edges`/`unresolved_refs` en brain.db +
panel System) fue **jubilado** (2026-06-08): aportaba menos y no se inyectaba
al contexto del agente. La migracion `schema_v4` se conserva como historia
inerte (las tablas existen vacias; no hay codigo que las consuma).
### Plugin Updates: chequeo de actualizaciones de plugins
- Sub-tab **Updates** dentro de Library (`src/components/library/PluginUpdates.tsx`)
que consume los comandos de backend `plugin_check_updates_bulk(force)` y
`plugin_changelog_summary(coordinate, installed_sha?)`.
- Compara el SHA instalado contra el ultimo SHA del marketplace por cada plugin,
marca cuales tienen actualizacion disponible y muestra el ultimo mensaje de
commit / resumen de changelog.
---
## Stack
| Capa | Tecnologia |
|---|---|
| Frontend (Control Center) | Tauri 2 + React 19 + TypeScript (`control-center/src/`) |
| Backend (Control Center) | Rust estable (`control-center/src-tauri/src/`) |
| Memoria (SoT) | SQLite (FTS5) en `~/.ultron/brain.db` |
| Indice denso | Qdrant nativo (`~/.ultron/qdrant-native/`), coleccion `ultron_memory`, E5 1024d |
| Embeddings | E5 (denso) via `crate::qdrant::embed_e5` dentro de `ultron-memory` |
| Sidecar CLI hooks | `ultron-memory` (logica canonica reusada por los hooks Node) |
| Scripting OS | PowerShell 5.1+ / scripts en `cockpit/` |
| Runtimes LLM | Claude Code (principal); Codex CLI opcional. Gemini CLI retirado 2026-06-19 (Google corto el free-tier OAuth); Gemini queda solo como fallback cloud del AI Router |
Binarios sidecar declarados en `control-center/src-tauri/Cargo.toml`:
`ultron-memory` (requiere la feature `qdrant`).
---
## Build
```bash
# desde control-center/
npm install
npm run build:app # = kill-app + tauri build (genera el ejecutable de escritorio)
```
Otros scripts utiles (en `control-center/package.json`):
```bash
npm run dev # vite dev server (frontend)
npm run tauri # CLI de Tauri
npm test # vitest (frontend)
```
> Nota Windows: `build:app` ejecuta primero `kill-app` para cerrar cualquier
> instancia en marcha; un binario obsoleto es la causa habitual de "no se ha
> aplicado el cambio". Verifica HEAD y rebuild antes de re-implementar.
---
## Estructura de carpetas
```
~/.ultron/
├── brain.db # SQLite — fuente de verdad de la memoria
├── qdrant-native/ # binario nativo de Qdrant (indice denso derivado)
├── qdrant_storage/ # datos persistidos por Qdrant
├── control-center/ # la app Tauri 2 + React 19
│ ├── src/ # frontend React/TS (componentes, tabs)
│ │ └── components/ # Dashboard, AIRouter, Library, Projects, ...
│ └── src-tauri/
│ └── src/
│ ├── memory/ # kernel de memoria (service, sqlite_store,
│ │ # qdrant_index, capture, redaction, texthash, ...)
│ ├── commands/ # comandos Tauri por dominio (memory, ai_router,
│ │ # projects, system_ops, ...)
│ ├── ai_router/ # AI Router (mod/exec/health/providers/seed/store/types)
│ ├── orchestrator/ # mod/orchestrate/ranking/rules/types_model
│ └── bin/ # sidecar ultron-memory
├── cockpit/ # config + estado en JSON/markdown
│ └── ai-router/ # providers.json, zones.json, metrics.json
├── personality.json # tonos del usuario (LOCAL, gitignored; se
│ # auto-siembra desde los seeds compilados)
├── hooks/ # hooks de ciclo de vida
├── skills/ # skills core (SKILL.md; catalogo curado no se publica)
├── plans/ projects/ # planes y proyectos
├── sessions/ # logs de sesion / telemetria de routing
└── docs/ # documentacion ampliada
```
---
## Estado actual
- **Memoria**: kernel canonico activo. SoT = `brain.db`; indice denso `ultron_memory`
(E5 1024d) sincronizado en escritura; recall unificado denso+sparse con RRF
operativo (degrada a sparse-only sin Qdrant). Write-path con redaccion de
secretos y dedupe por content_hash cableados y testeados.
- **Captura automatica**: Stop hook -> `capture_session` -> candidatos al inbox
gobernado; aprobacion/rechazo humano via comandos de inbox.
- **AI Router**: routing real con cadena primario/fallback, deteccion de claves
y telemetria de uso/ahorro; sin sidecar LiteLLM.
- **Tonos**: deteccion determinista en el orchestrate (paridad JS/Rust del
detector verificada con gate 16/16); editor visual en Library -> Tones y
playground de deteccion. `personality.json` local (gitignored) con seeds
publicables compilados; limite duro: el tono solo aplica al chat, jamas a
artefactos.
- **Detector de texto IA** (apoyo TFG): hook PostToolUse que avisa cuando la
prosa escrita "canta" a IA + Lab de patrones deterministas sobre el catalogo
de investigacion; matcher con CLI y banco de casos. Senala, no reescribe.
- **UI (Control Center, v15.8.0)**: barra lateral con Dashboard, Usage, AI Router,
System (con sub-tabs de Hooks/Schedules), MCPs,
Library (sub-tabs Skills/Agents/Rules/**Updates**), **Memory**, Notes,
Learn, Sessions, Projects, Finance (solo build local con `VITE_FINANCE=1`),
Settings y Notifications. La pestana **Memory**
esta **viva** (re-anadida 2026-06-04, `Sidebar.tsx`): expone el inbox de
candidatos (aprobar/rechazar/editar) y la salud de `brain.db`; el kernel de
memoria sigue siendo solo-backend, pero su gobierno human-in-the-loop se hace
desde esta pestana (ademas de los comandos).
---
## Licencia
MIT — ver [`LICENSE`](LICENSE). Copyright (c) 2026 Rodrigo Fernandez.
This server cannot be deployed
Maintenance
ActivityActive
ResponsivenessNo issues