---
name: list_resumable_claudes
kind: function
lang: go
domain: infra
version: "1.0.0"
purity: impure
signature: "func ListResumableClaudesFrom(claudeDir string) ([]ResumableClaude, error) | func ListResumableClaudes() ([]ResumableClaude, error)"
description: "Lista las sesiones de Claude Code CERRADAS que se pueden reabrir con `claude --resume <sessionId>` (Linux). Escanea ~/.claude/sessions/*.json para construir el conjunto de sessionIds VIVOS (mismo criterio anti-PID-reciclado que list_claude_fleet: procStart == campo 22 de /proc/<pid>/stat), luego recorre ~/.claude/goals/*.json y devuelve cada sesion cuyo proceso NO esta vivo y que tiene un goal no vacio. Cada entrada lleva session_id, goal, emojis y name (rename) del goal.json, y last_active = mtime del goal.json. Ordenadas por last_active desc y limitadas a 40. Pieza de datos del picker de resume de la app TUI fleetview."
tags: [claude-fleet, infra, claude, session, resume, proc, tui]
uses_functions: [list_claude_fleet_go_infra]
uses_types: [resumable_claude_go_infra]
returns: [resumable_claude_go_infra]
returns_optional: false
error_type: "error_go_core"
imports: []
params:
  - name: "claudeDir"
    desc: "Directorio raiz de Claude Code a escanear (ej. /home/enmanuel/.claude). ListResumableClaudesFrom lo recibe explicito (testeable con t.TempDir()); ListResumableClaudes lo resuelve via os.UserHomeDir() + .claude."
output: "Slice de ResumableClaude (resumable_claude_go_infra), una entrada por sesion CERRADA con goal en goals/<id>.json. Cada entrada lleva SessionID (basename del goal.json sin .json), Goal, Emojis, Name (rename) y LastActive (mtime del goal.json en epoch segundos). Excluye las sesiones cuyo proceso sigue vivo (ya en la flota) y las que no tienen goal. Ordenado por LastActive descendente y capado a 40 resultados. Devuelve slice vacio (sin error) si la carpeta goals/ no existe; error si no se puede leer por otra causa."
tested: true
tests: ["TestListResumableClaudesFrom"]
test_file_path: "functions/infra/resumable_claude_test.go"
file_path: "functions/infra/resumable_claude.go"
notes: "Complementaria de list_claude_fleet_go_infra: aquella lista las sesiones VIVAS, esta las CERRADAS-pero-resumibles. Reutiliza los helpers procIsAlive/procStartTime del mismo paquete infra (definidos en functions/infra/list_claude_fleet.go) — no los redefine. El conjunto de vivos se construye desde sessions/*.json; el catalogo de candidatas desde goals/*.json. El sessionId de una candidata es el basename del goal.json (no hay sessions/<PID>.json para ella porque su proceso ya murio). LastActive es el mtime del archivo, no la actividad real de la conversacion. Build tag //go:build !windows (depende de /proc, no portable a Windows)."
---

## Ejemplo

```go
package main

import (
	"fmt"

	"fn-registry/functions/infra"
)

func main() {
	resumables, err := infra.ListResumableClaudes() // escanea ~/.claude
	if err != nil {
		panic(err)
	}
	for _, r := range resumables {
		fmt.Printf("%s %-40s  claude --resume %s\n", r.Emojis, r.Goal, r.SessionID)
	}
}
```

```go
// Variante testeable: escanea un directorio arbitrario (fixtures en tests).
resumables, _ := infra.ListResumableClaudesFrom("/home/enmanuel/.claude")
fmt.Println(len(resumables), "sesiones reabribles")
```

## Cuando usarla

Cuando necesites poblar un picker de "reanudar" en la TUI fleetview (o cualquier UI/automatizacion equivalente): te da las sesiones de Claude Code que ya cerraste pero que tenian un objetivo guardado, listas para `claude --resume <session_id>`. Excluye las que siguen vivas (esas ya estan en la flota, las lista `list_claude_fleet_go_infra`). Usa `ListResumableClaudesFrom` en tests (inyectando un directorio con fixtures) y `ListResumableClaudes` en runtime real.

## Gotchas

- **Impura: lee el filesystem y /proc.** No es determinista entre llamadas (las sesiones nacen y mueren). Solo lectura — nunca relanza ni mata nada.
- **El statusline purga goals viejos.** Las sesiones de mas de ~7 dias suelen tener su `goals/<id>.json` purgado por el statusline, asi que dejan de aparecer aqui aunque `claude --resume` siga pudiendo reabrirlas. Esta funcion solo ve lo que queda en `goals/`.
- **PID reciclado.** El conjunto de "vivos" usa el mismo guardado anti-PID-reciclado que `list_claude_fleet`: un PID reasignado a otro proceso NO marca la sesion como viva (procStart != campo 22 de /proc/<pid>/stat), por lo que su goal seguira saliendo como resumible correctamente.
- **Orden por mtime, no por actividad real.** `LastActive` es el `mtime` del `goal.json`, que se toca cuando el statusline reescribe el objetivo/fase — no es el instante exacto del ultimo mensaje de la conversacion. Es una aproximacion "lo mas reciente arriba", no un timestamp exacto de actividad.
- **Cap a 40.** Solo se devuelven las 40 mas recientes; si hay mas goals cerrados, los antiguos se omiten.
- **Goals sin goal o ilegibles se omiten** silenciosamente. Un `goal.json` con `goal` vacio (o solo espacios) no es resumible (no hay trabajo que reanudar). Archivos no-`.json` y JSON corrupto se ignoran.
- **/proc no es portable.** Build tag `//go:build !windows`; depende de `/proc/<pid>/stat` (Linux) para decidir que sesiones estan vivas.
