---
id: "0109"
title: "App skill_tree: mapa interactivo de issues+flows en anillos concentricos por estado (roadmap)"
status: in-progress
type: epic
domain:
  - meta
  - cpp-stack
scope: cross-stack
priority: media
depends: []
blocks: []
related:
  - "0069"
  - "0085"
  - "0086"
  - "0087"
  - "0100"
created: 2026-05-17
updated: 2026-05-17
tags:
  - skill-tree
  - roadmap
  - meta
  - cpp
  - imgui
  - gamification
---

# 0109 — skill_tree app (roadmap)

## Vision

App C++ ImGui que muestra los **79 issues + 7 flows** del registry como un mapa de capacidades en **anillos concentricos por estado** (centro = `completado`, exterior = `locked`/`deferred`), con **sectores radiales por dominio**. Click en nodo → panel `Inspector` con DoD + funciones del registry asociadas + 2 botones:

- **Generate ideas (`claude -p`)** → escribe a tabla `idea_drafts` para revision manual.
- **Run autonomous-task (`fn-orquestador`)** → spawn subagente en sandbox `auto/<issue>` con tail de logs.

Centro NO es nodo — es **HUD overlay** con LV, XP, conteos por dominio. Animacion lerp 1s cuando un nodo migra de anillo (cambio de status). Sin fisicas — layout estatico y determinista.

## Por que

- Discovery visual: lo que hoy es `ls dev/issues/` + lectura individual de 79 .md, se reduce a panoramica de 5s.
- Dispatcher unificado: lanzar `claude -p` o `/autonomous-task` desde 1 click contextual (hoy: copiar ID + tipear comando).
- Gamificacion derivada (XP/nivel) sin inflar nada artificial — todo deriva de trabajo real (status frontmatter + telemetria).

## No-goals (fuera de scope)

- NO editor de issues. Solo lectura + dispatch. Editar issue = boton "Open in editor" → `code <path>`.
- NO orquestador propio. Reusa `fn-orquestador` + `/autonomous-task` (issue 0069).
- NO base de datos paralela de issues. `registry.db` y `dev/issues/*.md` siguen siendo fuente unica.

## Modelo

### Tipos de nodo

| Tipo | Origen | Ring | Render |
|---|---|---|---|
| Issue (epic) | `dev/issues/NNNN-*.md` (`type=epic`) | segun status | nodo grande, color accent del dominio |
| Issue (feature/bugfix/refactor/...) | mismo, otros types | segun status | nodo medio, tono mas claro |
| Flow | `dev/flows/NNNN-*.md` | segun status (flow.status) | nodo distinto shape (rombo) |

### Aristas

- `issue.depends` / `issue.blocks` → DAG (linea solida).
- `flow.related_issues` → linea punteada flow → issue.
- On-hover: aristas al cinturon perimetral de funciones del registry (`uses_functions` cruzado con tags del issue).

### Estado lock/unlock (DERIVADO — nunca manual)

| Status visual | Regla |
|---|---|
| `done` | `status=completado` (issues) o `status=completed` (flows) |
| `in-progress` | `status=in-progress` |
| `unlocked` | `status=pendiente` Y todos `depends[]` resueltos |
| `locked` | `status=pendiente` Y algun `depends[]` no resuelto |
| `bloqueado` | `status=bloqueado` |
| `deferred` | `status=deferred` |

Flows sin `depends` usan `related_issues` — flow unlocked si todos los related estan done.

### XP / nivel

- `xp_value` por tipo: `epic=10, feature=3, bugfix=1, refactor=2, chore=1, docs=1, flow=5`.
- `xp_total = SUM(xp_value WHERE status in {completado, completed})`.
- `level = floor(sqrt(xp_total))`.
- HUD muestra: `LV X · N done · M open · K in-progress · domains mastered: ...`.

## Layout: anillos concentricos

| Ring | Radio (px) | Que contiene | Notas |
|---|---|---|---|
| 0 | 0 - 150 | `completado` | Si > 30 nodos, mostrar top-N por recencia + bucket "+N mas" |
| 1 | 150 - 280 | `in-progress` | Pulse animation suave |
| 2 | 280 - 450 | `unlocked` pendiente | Color pleno, clickable |
| 3 | 450 - 650 | `locked` (depends sin cumplir) | Gris, aristas hacia bloqueantes |
| 4 | 650+ | `deferred` + `bloqueado` | Semi-transparente |

Cada ring subdividido en **18 sectores radiales = 1 dominio** (allowlist de `dev/TAXONOMY.md`). Aristas curvas hacia el centro siguiendo el sector. Cuando un issue cambia status → lerp 1s entre posicion vieja y nueva.

## Stack tecnico

- **App C++ ImGui** via `fn::run_app` (scaffolder `init_cpp_app_bash_pipelines`).
- **Viz**: `graph_renderer_cpp_viz` (solo draw — sin force layout) + `graph_viewport_cpp_viz` + `graph_labels_cpp_viz` + `graph_spatial_hash_cpp_core` (picking O(1)).
- **Layout**: nueva fn `compute_ring_layout_cpp_core` (pure) — input `[{node_id, status, domain, recency}]`, output `[{node_id, x, y, ring, sector}]`.
- **Parser**: nueva fn `parse_md_frontmatter_cpp_core` (pure) — extrae bloque `---...---` + parse YAML simple (subset: key:value, key:list).
- **BD propia**: `apps/skill_tree/local_files/skill_tree.db` con tablas:
  - `node_state_cache` (denormalizacion para render rapido)
  - `agent_jobs` (claude -p + fn-orquestador spawns)
  - `xp_events` (append-only para timeline)
  - `idea_drafts` (drafts de `claude -p` antes de promover a proposal)
- **Registry.db**: read-only (`?mode=ro`), solo para enriquecer Inspector con info de `functions/types`.

## Sub-issues (rompimiento)

| ID | Titulo | DoD resumido |
|---|---|---|
| 0109a | App shell + parsers | Scaffolder corre. App abre. Lee 79 issues + 7 flows. Log conteos en stdout. e2e_checks build OK. |
| 0109b | Layout anillos + render estatico | Nodos pintados en su ring+sector. Aristas depends/related visibles. Sin interaccion clic. |
| 0109c | Panel Inspector + estado derivado | Click nodo → panel derecho con DoD + uses_functions. Lock/unlock derivado de depends. Reload manual F5. |
| 0109d | HUD XP + animacion migracion | Overlay HUD arriba-izq. Lerp 1s en cambio de status. xp_events append-only. |
| 0109e | Boton Ideas (claude -p → drafts) | Spawn `claude -p` con prompt contextual. Persiste en `idea_drafts`. UI aprobar/rechazar → proposals. |
| 0109f | Boton Auto-run (fn-orquestador) | Spawn `Agent(fn-orquestador)` background. Panel inferior con tail logs. Barra progreso vive (`task_runs.checks_pass/total`). |

## Riesgos / mitigaciones

| Riesgo | Mitigacion |
|---|---|
| Ring 0 con ~72 done satura visualmente | Top-N por recencia + bucket "+N mas..." expandible |
| 18 sectores * 158 nodos = legibilidad pobre | Zoom semantico: zoom-out muestra solo epics + flows |
| `claude -p` puede consumir tokens en bucle | Rate-limit UI: 1 invocacion por nodo por hora (`idea_drafts.last_request_at`) |
| Drift status del .md vs cache | F5 manual fuerza re-scan. Sin file watcher en fase A. |
| Parser YAML C++ frágil con campos exoticos | Test golden sobre los 79 issues actuales antes de mergear 0109a |

## DoD del epic

- [ ] App `skill_tree` indexada en `registry.db` con `framework=imgui`, trio icon completo, `e2e_checks` declarados, `uses_functions` no vacio.
- [ ] Compila en Linux + Windows. Desplegada via `redeploy_cpp_app_windows`.
- [ ] Tarjeta visible en `app_hub_launcher`.
- [ ] Los 6 sub-issues (a-f) mergeados a master de su sub-repo Gitea.
- [ ] Pipeline `fn doctor cpp-apps` limpio para `skill_tree`.
- [ ] `fn doctor uses-functions` sin drift para `skill_tree`.

## Funciones nuevas previstas (delegar a fn-constructor)

1. `parse_md_frontmatter_cpp_core` (pure) — parser frontmatter YAML simple en C++.
2. `compute_ring_layout_cpp_core` (pure) — posiciones determinsticas por anillo+sector.
3. `spawn_claude_p_bash_infra` o `_go_infra` — lanza `claude -p "<prompt>"` con timeout + captura stdout JSON. Reusable.

## Decisiones

| Tema | Decision | Razon |
|---|---|---|
| Centro del mapa | HUD overlay, NO nodo | Centro = "estado actual del usuario" — no es un item, es un agregado. |
| Layout | Estatico anillos+sectores | Sin fisicas. Usuario dijo "no quiero que se muevan, nos volveran locos". |
| Animacion | Lerp 1s entre rings | Da sensacion de progreso sin caos visual. |
| Boton Ideas dest | `idea_drafts` (revision manual) | Evita ruido en `proposals`. |
| Refresh | F5 manual | Simplicidad MVP. File watcher en fase posterior. |
| Service tag | NO | App interactiva, no daemon. |
| Ubicacion | `apps/skill_tree/` | Meta-tool del registry entero, no de proyecto. |
