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.
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
---
|
||||
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.
|
||||
Reference in New Issue
Block a user