---
name: tmux_map_claude_panes
kind: function
lang: go
domain: infra
version: "1.0.0"
purity: impure
signature: "func TmuxMapClaudePanes(socket string) (map[int]string, error)"
description: "Devuelve un mapa claudePID -> window_id de todos los panes de un socket tmux aislado (tmux -L <socket>) cuyo proceso de pane (o un descendiente directo) sea un proceso `claude`. Lee /proc para decidir si cada #{pane_pid} es o tiene como hijo un comm == 'claude'. Permite a la TUI fleetview saber que Claude de su lista ya vive en la sesion fleet (y por tanto es conmutable) y en que window. Capa de control tmux de fleetview."
tags: [claude-fleet, infra, tmux, claude, proc, fleet, tui]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
params:
  - name: "socket"
    desc: "Nombre del socket tmux aislado (tmux -L <socket>). En fleetview es 'fleet'. Escanea TODOS los panes del servidor de ese socket (list-panes -a)."
output: "map[int]string con clave = PID del proceso claude encontrado bajo cada pane y valor = window_id (@N) de ese pane. Panes sin claude (ni pane_pid ni hijo directo con comm 'claude') se omiten. Mapa vacio (sin error) si ningun pane corre claude. Error si socket viene vacio o si `tmux list-panes -a` falla."
tested: true
tests: ["TestTmuxMapClaudePanesNoClaude", "TestTmuxMapClaudePanesEmptySocket", "TestProcCommSelf", "TestFindClaudePIDDetectsChild"]
test_file_path: "functions/infra/tmux_map_claude_panes_test.go"
file_path: "functions/infra/tmux_map_claude_panes.go"
notes: "Build tag //go:build !windows (depende de /proc). Comparte runTmux con tmux_new_claude_window y tmux_swap_window_into_console (mismo paquete infra). Deteccion claude: lee /proc/<pid>/comm; si no es 'claude', recorre hijos directos. Hijos directos via /proc/<pid>/task/<pid>/children (rapido, requiere CONFIG_PROC_CHILDREN); fallback a escanear /proc/*/stat por PPID (campo 4, parseando el comm entre parentesis tomando lo que hay tras el ULTIMO ')'). En produccion cada pane corre `exec claude`, asi que pane_pid == claude PID y basta el primer comm; el barrido de hijos es robustez para shells intermedios."
---

## Ejemplo

```go
package main

import (
	"fmt"

	"fn-registry/functions/infra"
)

func main() {
	// Que Claude ya vive en la sesion fleet (socket aislado 'fleet') y donde.
	byPID, err := infra.TmuxMapClaudePanes("fleet")
	if err != nil {
		panic(err)
	}
	for claudePID, windowID := range byPID {
		fmt.Printf("claude pid=%d -> window %s\n", claudePID, windowID)
	}
}
```

## Cuando usarla

Cuando la TUI fleetview refresca su lista de Claudes y necesita marcar cuales ya estan dentro de la sesion `fleet` (conmutables con `tmux_swap_window_into_console`) y en que window. Cruza el PID de cada entrada de `list_claude_fleet` contra este mapa: si el PID esta, el Claude es swap-able y el valor es su `window_id`.

## Gotchas

- Mapea por PID de claude, no por pane_pid: si el pane corre un shell que lanzo claude como hijo, la clave es el PID del hijo claude.
- Solo busca hijos DIRECTOS (un nivel). En produccion fleetview usa `exec claude`, asi que pane_pid == claude PID y el caso comun no necesita el barrido.
- Depende de `/proc` (Linux): build tag `//go:build !windows`. En kernels sin `CONFIG_PROC_CHILDREN` cae a escanear `/proc/*/stat` por PPID, mas lento pero equivalente.
- Lee `comm` (truncado a 15 chars por el kernel); `claude` cabe entero, sin riesgo de truncado.
- Panes sin claude se omiten silenciosamente: un mapa vacio significa "ningun Claude vivo en este socket", no es error.
- Opera SIEMPRE sobre el socket aislado (`tmux -L <socket>`), escaneando todos sus panes con `list-panes -a`.
