Files
claude_session/app.md
T
agent d9982d853d feat: scaffold claude_session — daemon de sesion claude caliente (NDJSON)
Daemon de larga vida que mantiene una TUI claude interactiva viva y responde
prompts en ~2.7s, embebible como subproceso via NDJSON por stdin/stdout.

Arranca mitmproxy (addon tee_anthropic_sse) + claude TUI en PTY (creack/pty
directo, persistente) una vez. Cada prompt se teclea en la TUI viva; la
respuesta se lee del SSE de la red (exacta, corta en message_stop). El cold
start (~7s) se paga una vez; los siguientes mensajes ~2.7s, con memoria entre
turnos. Protocolo: send/restart/shutdown -> ready/text_delta/result/restarted.

Validado: 2.7s por mensaje en caliente (vs 15s parseando TUI, vs 9s one-shot),
restart relanza la conversacion. Reusa tee_anthropic_sse_py_cybersecurity +
vt_render_go_tui.
2026-06-04 00:40:29 +02:00

155 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: claude_session
lang: go
domain: infra
version: 0.1.0
description: "Daemon de larga vida que mantiene una sesion claude (TUI interactiva) caliente y responde prompts rapido, pensado para embeber en una app como subproceso via NDJSON por stdin/stdout. Arranca mitmproxy + claude TUI una vez; cada prompt se teclea en la TUI viva y la respuesta se lee del SSE de la red (exacta, corta en message_stop). Primer mensaje paga el arranque (~7s); los siguientes ~2-3s, con memoria entre turnos. Comando restart para reiniciar la conversacion."
tags: [cli, claude, daemon, session, ndjson, mitmproxy, web-proxy, streaming]
uses_functions:
- tee_anthropic_sse_py_cybersecurity
- vt_render_go_tui
uses_types: []
framework: ""
entry_point: "main.go"
dir_path: "apps/claude_session"
icon:
phosphor: "lightning"
accent: "#f59e0b"
e2e_checks:
- id: build
cmd: "go build -o claude_session ."
timeout_s: 60
- id: bad_cmd
cmd: "echo '{\"cmd\":\"bogus\"}' | timeout 30 ./claude_session 2>/dev/null | grep -q 'unknown cmd' && echo ok || true"
expect_stdout_contains: "ok"
timeout_s: 40
---
# claude_session
## Que hace
Daemon que mantiene una sesion `claude` (TUI interactiva real, **nunca `claude -p`**) **caliente**
y responde prompts en ~2-3s. Pensado para embeberse en una app como subproceso de larga vida,
controlado por NDJSON por stdin/stdout.
Arranca **una vez** un mitmproxy (addon `tee_anthropic_sse`) y la TUI de claude en un PTY, y los
mantiene vivos. Cada prompt se teclea en la TUI viva; la respuesta se lee **del SSE de la red**
(exacta, token a token, cortada por `message_stop`). El cold start (~7s) se paga una sola vez al
arrancar; los mensajes siguientes solo pagan la generacion, y la conversacion **mantiene contexto
entre turnos**.
## Latencia (medida)
| Camino | por mensaje |
|---|---|
| `claude_pipe` (parsear render TUI) | ~15s |
| `claude_wire` (interceptar red, one-shot) | ~9s |
| **`claude_session` (daemon caliente)** | **~2.7s** (+ ~7s de arranque, una vez) |
## Protocolo NDJSON
Un objeto JSON por linea.
**stdin (comandos):**
```json
{"cmd":"send","prompt":"hola"}
{"cmd":"restart"}
{"cmd":"shutdown"}
```
**stdout (eventos):**
```json
{"type":"ready"}
{"type":"text_delta","text":"H"}
{"type":"text_delta","text":"ola"}
{"type":"result","result":"Hola"}
{"type":"restarted"}
{"type":"error","message":"..."}
```
- `send`: teclea el prompt en la TUI viva, emite `text_delta` segun llegan del SSE, luego `result`
y un `ready` cuando la TUI vuelve al input box.
- `restart`: mata y relanza la TUI (conversacion **nueva, sin memoria**), mantiene el mitmproxy.
Emite `restarted` + `ready`.
- `shutdown`: mata todo y termina.
## Arquitectura
```
mitmdump + tee_anthropic_sse (persistente — capta el SSE de /v1/messages)
claude TUI en PTY (creack/pty) (persistente — NO se mata entre prompts)
loop NDJSON (teclea prompts, lee el wire, multiplexa por message_stop)
```
Reusa `tee_anthropic_sse_py_cybersecurity` (addon SSE) y `vt_render_go_tui` (render del PTY para
detectar readiness del input box).
## Embeber en una app
La app arranca el binario como subproceso de larga vida y habla por sus stdin/stdout:
```python
import subprocess, json
p = subprocess.Popen(["claude_session", "--cwd", "/home/enmanuel/fn_registry"],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True, bufsize=1)
# esperar {"type":"ready"}
def send(prompt):
p.stdin.write(json.dumps({"cmd": "send", "prompt": prompt}) + "\n"); p.stdin.flush()
for line in p.stdout:
ev = json.loads(line)
if ev["type"] == "result":
return ev["result"]
```
## Ejemplo (NDJSON por stdin)
```bash
cd apps/claude_session && go build -o claude_session .
printf '%s\n' \
'{"cmd":"send","prompt":"di solo OK"}' \
'{"cmd":"send","prompt":"di solo DOS"}' \
'{"cmd":"shutdown"}' \
| ./claude_session --cwd /home/enmanuel/fn_registry
# {"type":"ready"}
# {"type":"text_delta","text":"O"} ... {"type":"result","result":"OK"} {"type":"ready"}
# {"type":"text_delta","text":"D"} ... {"type":"result","result":"DOS"} {"type":"ready"}
```
## Flags
| Flag | Default | Que hace |
|---|---|---|
| `--cwd` | `~/fn_registry` | Directorio de la sesion claude (MCP aprobados). |
| `--port` | `8901` | Puerto del mitmproxy. |
| `--root` | `~/fn_registry` | Raiz del registry (para localizar el addon). |
| `--addon` | `<root>/python/functions/cybersecurity/tee_anthropic_sse.py` | Addon mitmproxy. |
| `--ca` | `~/.mitmproxy/mitmproxy-ca-cert.pem` | CA de mitmproxy. |
| `--bin` | `claude` | Binario claude. |
| `--warmup` | `12s` | Espera maxima a que la TUI este lista. |
## Prerrequisitos
- `mitmproxy` (`mitmdump` en PATH) + CA generada y confiada via `NODE_EXTRA_CA_CERTS`.
- `claude` en el PATH.
## Gotchas
- **Readiness post-restart prematura**: tras `restart`, el `ready` puede emitirse antes de que la
TUI termine de cargar (detecta el input box `` pronto). El primer `send` tras un restart puede
tardar mas (~5-6s en vez de ~2.7s) porque el input se teclea mientras claude aun arranca (se
bufferea, no se pierde). Refinamiento pendiente: readiness mas estricta (esperar que cese el
trafico de arranque en el proxy).
- **Sesion secuencial**: un prompt a la vez. No mandes un `send` mientras otro genera.
- **Memoria entre turnos**: la TUI viva acumula la conversacion (es una feature). Usa `restart`
para empezar de cero.
- **Requiere mitmproxy + CA** (`NODE_EXTRA_CA_CERTS`); depende de que claude no haga TLS pinning
(hoy no lo hace).
- **Una interaccion dispara varias /v1/messages**; el addon filtra por `has_tools` para seguir la
respuesta principal.
- **Linux/Unix** (PTY POSIX).
- **Es trafico de tu propia cuenta y maquina** — observabilidad local.