diff --git a/playground/README.md b/playground/README.md
deleted file mode 100644
index 5cc7e8c..0000000
--- a/playground/README.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# claude_wire — chat web (playground)
-
-Chat en el navegador sobre `claude_wire`: el texto de la respuesta se obtiene
-interceptando el SSE del modelo en la red (no parseando el render de la terminal).
-
-Backend Go con SSE (`web/server.go`) que, por cada mensaje, lanza `claude_wire`
-y reenvía su NDJSON (`text_delta` + `result`) al navegador. Frontend vanilla
-(`web/index.html`), sin frameworks ni node_modules. No se indexa (playground del
-padre).
-
-## Prerrequisitos
-
-- `mitmproxy` instalado (`mitmdump` en el PATH) + CA generada
- (`~/.mitmproxy/mitmproxy-ca-cert.pem`).
-- Binarios compilados:
- - `apps/claude_pipe/claude_pipe` (driver de la TUI).
- - `apps/claude_wire/claude_wire` (runner que intercepta el SSE).
-
-```bash
-cd apps/claude_pipe && CGO_ENABLED=1 go build -tags fts5 -o claude_pipe .
-cd ../claude_wire && go build -o claude_wire .
-```
-
-## Lanzar
-
-```bash
-cd apps/claude_wire/playground
-go run ./web # http://localhost:8100
-# o con flags:
-go run ./web --port 8100 --root /home/enmanuel/fn_registry --wire ../claude_wire
-```
-
-Abre `http://localhost:8100` y escribe. Cada mensaje dirige la TUI interactiva de
-claude por un mitmproxy y lee la respuesta del SSE de `api.anthropic.com`, token a
-token, exacta. Corta en `message_stop` (sin idle ciego): ~9s por respuesta.
-
-## vs el chat de claude_pipe
-
-| | `claude_pipe` chat (`:8099`) | `claude_wire` chat (`:8100`) |
-|---|---|---|
-| Texto | parseado del render (heurístico) | exacto del SSE de la red |
-| Streaming | snapshots del grid | token real |
-| Latencia | ~15s | ~9s |
-
-## Notas
-
-- Mensajes serializados (un `claude_wire` a la vez: usa un puerto mitmproxy fijo).
-- Sin memoria entre turnos (cada mensaje es una sesión claude one-shot).
diff --git a/playground/web/go.mod b/playground/web/go.mod
deleted file mode 100644
index f856045..0000000
--- a/playground/web/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module cw_web
-
-go 1.25.0
diff --git a/playground/web/index.html b/playground/web/index.html
deleted file mode 100644
index 0e11e3a..0000000
--- a/playground/web/index.html
+++ /dev/null
@@ -1,159 +0,0 @@
-
-
-
-
-
-claude_wire · chat (SSE interceptado)
-
-
-
-
-
- claude_wire · chat
- texto exacto del modelo, interceptado del SSE de la red
-
-
-
-
-
sistema
Escribe un mensaje. Cada turno dirige la TUI interactiva de claude por un mitmproxy y lee la respuesta DEL CABLE (el SSE de api.anthropic.com), no de la pantalla. Texto exacto, token a token, sin memoria entre mensajes.
-
-
-
-
- Cada mensaje = captura del SSE via mitmproxy. Corta en message_stop (sin idle ciego). ~9s por respuesta; el grueso es el arranque de la TUI.
-
-
-
-
diff --git a/playground/web/server.go b/playground/web/server.go
deleted file mode 100644
index 3196a1a..0000000
--- a/playground/web/server.go
+++ /dev/null
@@ -1,123 +0,0 @@
-// Command server is a browser chat over claude_wire — the network-intercept path.
-// For each message it launches claude_wire, which drives the interactive claude TUI
-// through a mitmproxy and reads the model's SSE off the wire, then relays the
-// resulting NDJSON (text_delta + result) to the browser as Server-Sent Events.
-//
-// Versus the claude_pipe chat (which parses the terminal render), this one shows the
-// exact model text token by token and finishes as soon as the model's message_stop
-// arrives — no blind idle wait. ~9s vs ~15s per message.
-//
-// claude_wire uses a fixed mitmproxy port, so messages are serialized with a mutex
-// (a chat is sequential anyway: you wait for the reply before sending the next).
-//
-// Each message is an independent one-shot claude session (no memory across turns).
-//
-// Run:
-//
-// cd apps/claude_pipe && CGO_ENABLED=1 go build -tags fts5 -o claude_pipe . # the TUI driver
-// cd ../claude_wire && go build -o claude_wire . # the runner
-// cd playground && go run ./web # http://localhost:8100
-package main
-
-import (
- "bufio"
- _ "embed"
- "flag"
- "fmt"
- "log"
- "net/http"
- "os"
- "os/exec"
- "path/filepath"
- "sync"
-)
-
-//go:embed index.html
-var indexHTML []byte
-
-var (
- wireBin string
- root string
- one sync.Mutex // serialize: one claude_wire at a time (fixed proxy port)
-)
-
-func main() {
- port := flag.String("port", "8100", "port to listen on")
- bin := flag.String("wire", "/home/enmanuel/fn_registry/apps/claude_wire/claude_wire", "path to the claude_wire binary")
- rootDir := flag.String("root", "/home/enmanuel/fn_registry", "cwd for claude (MCP-approved repo)")
- flag.Parse()
-
- abs, err := filepath.Abs(*bin)
- if err != nil {
- log.Fatalf("resolve --wire: %v", err)
- }
- if _, err := os.Stat(abs); err != nil {
- log.Fatalf("claude_wire binary not found at %s — build it first:\n (cd .. && go build -o claude_wire .)", abs)
- }
- wireBin, root = abs, *rootDir
-
- http.HandleFunc("/", handleIndex)
- http.HandleFunc("/chat", handleChat)
-
- log.Printf("claude_wire web chat → http://localhost:%s (wire=%s root=%s)", *port, wireBin, root)
- log.Fatal(http.ListenAndServe(":"+*port, nil))
-}
-
-func handleIndex(w http.ResponseWriter, r *http.Request) {
- if r.URL.Path != "/" {
- http.NotFound(w, r)
- return
- }
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- _, _ = w.Write(indexHTML)
-}
-
-// handleChat runs claude_wire for the prompt and relays its NDJSON as SSE.
-func handleChat(w http.ResponseWriter, r *http.Request) {
- prompt := r.URL.Query().Get("prompt")
- if prompt == "" {
- http.Error(w, "missing prompt", http.StatusBadRequest)
- return
- }
- flusher, ok := w.(http.Flusher)
- if !ok {
- http.Error(w, "streaming unsupported", http.StatusInternalServerError)
- return
- }
- w.Header().Set("Content-Type", "text/event-stream")
- w.Header().Set("Cache-Control", "no-cache")
- w.Header().Set("Connection", "keep-alive")
- w.Header().Set("X-Accel-Buffering", "no")
-
- // Serialize: claude_wire binds a fixed mitmproxy port.
- one.Lock()
- defer one.Unlock()
-
- cmd := exec.CommandContext(r.Context(), wireBin, "--prompt", prompt, "--cwd", root)
- stdout, err := cmd.StdoutPipe()
- if err != nil {
- sse(w, flusher, "error", fmt.Sprintf(`{"message":%q}`, err.Error()))
- return
- }
- cmd.Stderr = os.Stderr
- if err := cmd.Start(); err != nil {
- sse(w, flusher, "error", fmt.Sprintf(`{"message":%q}`, err.Error()))
- return
- }
-
- sc := bufio.NewScanner(stdout)
- sc.Buffer(make([]byte, 1024*1024), 1024*1024)
- for sc.Scan() {
- sse(w, flusher, "", sc.Text())
- }
- _ = cmd.Wait()
- sse(w, flusher, "done", "{}")
-}
-
-func sse(w http.ResponseWriter, f http.Flusher, event, data string) {
- if event != "" {
- fmt.Fprintf(w, "event: %s\n", event)
- }
- fmt.Fprintf(w, "data: %s\n\n", data)
- f.Flush()
-}