--- name: claude_pipe lang: go domain: infra version: 0.1.0 description: "Alternativa a 'claude -p' que obtiene la respuesta de claude como dato PARSEANDO su TUI interactiva: captura el render via PTY, reconstruye el layout y extrae los turnos + la respuesta final. Emite JSON con el mismo shape que 'claude -p --output-format json'. Para interaccion programatica robusta prefiere el camino stream-json (claude_stream_go_core); esta app es la variante que va a traves de la TUI." tags: [cli, claude, terminal, pty, tui, parser] uses_functions: - pty_capture_idle_go_infra - vt_render_go_tui - parse_claude_tui_go_tui uses_types: - claude_tui_parse_go_tui - claude_turn_go_tui framework: "" entry_point: "main.go" dir_path: "apps/claude_pipe" icon: phosphor: "faders" accent: "#0ea5e9" e2e_checks: - id: build cmd: "CGO_ENABLED=1 go build -tags fts5 -o claude_pipe ." timeout_s: 120 - id: smoke_fake_text cmd: "./claude_pipe --bin ./tests/fake_claude.sh --warmup 300ms --step-delay 100ms --idle 700ms --max 5s --format text test" expect_stdout_contains: "RESPUESTA_FAKE_OK" timeout_s: 15 - id: smoke_fake_json cmd: "./claude_pipe --bin ./tests/fake_claude.sh --warmup 300ms --step-delay 100ms --idle 700ms --max 5s --format json test" expect_stdout_contains: "\"result\":\"RESPUESTA_FAKE_OK\"" timeout_s: 15 --- # claude_pipe ## Que hace Devuelve la respuesta de `claude` como dato **parseando su TUI interactiva**, en lugar de usar `claude -p`. Internamente lanza el `claude` interactivo dentro de un pseudo-terminal, captura el render de la pantalla, reconstruye el layout 2D, y extrae los turnos de la conversacion mas la respuesta final del asistente. La salida por defecto imita `claude -p --output-format json`. Es la respuesta a "quiero parsear la TUI y que devuelva lo mismo que `claude -p`". Para la mayoria de los casos programaticos el camino limpio es `stream-json` (ver `claude_stream_go_core`), que no toca la TUI; `claude_pipe` existe para cuando se quiere expresamente ir a traves de la TUI. ## Arquitectura (composicion de funciones del registry) ``` claude (TUI) ─pty_capture_idle_go_infra─▶ bytes crudos del terminal ─vt_render_go_tui──────────▶ pantalla como texto plano (layout 2D) ─parse_claude_tui_go_tui───▶ ClaudeTUIParse {Turns, Answer} ─(esta app)────────────────▶ JSON estilo claude -p / texto / turns ``` La app no aporta logica reutilizable: solo orquesta las tres funciones y elige el formato de salida. ## Formatos de salida (`--format`) | Formato | Salida | Equivale a | |---|---|---| | `json` (default) | `{"type":"result","subtype":"success","is_error":false,"result":""}` | `claude -p --output-format json` (campos esenciales) | | `text` | solo el texto de la respuesta | `claude -p` plano | | `turns` | el `ClaudeTUIParse` completo: cada turno visible (user/assistant/tool_use/tool_result) + answer | — (mas rico que `claude -p`) | | `screen` | el render de la pantalla sin parsear | debug | ## Ejemplo ```bash cd apps/claude_pipe CGO_ENABLED=1 go build -tags fts5 -o claude_pipe . # Respuesta como JSON (mismo shape que claude -p --output-format json) ./claude_pipe --cwd /home/enmanuel/fn_registry "responde unicamente con la palabra PONG" # {"type":"result","subtype":"success","is_error":false,"result":"PONG"} # Solo el texto ./claude_pipe --format text --cwd /home/enmanuel/fn_registry "resume el README en 3 lineas" # Todos los turnos visibles (incluye tool_use/tool_result que la TUI muestra) ./claude_pipe --format turns --cwd /home/enmanuel/fn_registry "lee main.go y resumelo" # Prompt por stdin echo "explica este error" | ./claude_pipe --cwd /home/enmanuel/fn_registry ``` ## Flags | Flag | Default | Que hace | |---|---|---| | `--prompt` | — | Prompt a enviar. Si vacio, se toma del arg posicional o de stdin. | | `--format` | `json` | `json` \| `text` \| `turns` \| `screen`. | | `--cwd` | — | Directorio donde se lanza claude (usa un repo con los MCP aprobados, para saltar el dialogo de arranque). | | `--bin` | `claude` | Binario claude a lanzar (o un fake para tests). | | `--warmup` | `4s` | Espera antes de enviar el prompt, para que la TUI cargue. | | `--step-delay` | `600ms` | Espera entre teclear el prompt y pulsar Enter. | | `--idle` | `4s` | Corta la captura tras este silencio (respuesta terminada de renderizar). | | `--max` | `120s` | Timeout duro de toda la captura. | ## Cuando usarla - Cuando quieras la respuesta de una sesion `claude` como dato yendo **a traves de la TUI** (no via `claude -p`). - Para auditar/scriptear lo que la TUI muestra y obtener ademas los `tool_use`/`tool_result` visibles (`--format turns`). Si no necesitas pasar por la TUI, usa `claude_stream_go_core` (stream-json) — es mas robusto. ## Gotchas - **No reemplaza 1:1 a `claude -p`**: el campo `result` (la respuesta) coincide, pero NO se extraen los metadatos (`cost`, `tokens`, `session_id`, `duration_ms`) porque la TUI no los expone de forma fiable. - **Truncacion por scroll**: la captura solo ve el grid visible (40x120). Una respuesta mas larga que la pantalla se trunca por arriba (el render no guarda scrollback). Respuestas cortas/medias van bien. - **Heuristico y version-dependiente**: el parser asume el layout actual de la TUI de claude. Si claude cambia su UI, hay que ajustar `parse_claude_tui_go_tui`. - **Dialogo de arranque**: en un cwd cuyos MCP no estan aprobados, claude bloquea con "new MCP servers found". Usa `--cwd `. - **Latencia**: anade `warmup` + `idle` (por defecto ~8s de overhead) sobre el tiempo de respuesta de claude. `claude -p` no tiene ese overhead. Es el precio de ir por la TUI. - **Linux/Unix only**: hereda el PTY POSIX de `pty_capture_idle_go_infra`. - **Streaming**: esta version es one-shot (espera la respuesta completa y luego parsea). El streaming incremental de la TUI esta planificado como fase 2 (requiere capturar snapshots durante el render).