Me armé un panel físico para manejar 10 Claude Code a la vez (Stream Deck + iTerm2)
Diez terminales, cada una con un agente trabajando, y yo apretando “1” para aprobar cosas. Cómo lo resolví con hooks, un CLI escondido de iTerm2 y un plugin hecho con el mismo Claude que controla.
Son las 11 de la mañana. Tengo siete tabs de iTerm2 abiertas y en cada una hay una sesión de Claude Code trabajando en algo distinto: una migra un codemod de botones, otra revisa la retención de buckets en GCP, otra está en plan mode pensando cómo reestructurar un módulo de presupuestos. iTerm me pinta cada tab con un puntito: naranja trabajando, verde quieta, azul esperándome.
Y ahí está el problema. Cada vez que uno se pone azul tengo que ir a esa tab (Cmd+3, ¿o era Cmd+4?), leer qué pide, apretar 1, y volver a lo que estaba haciendo. Diez veces por hora. En este modo de trabajo, el cuello de botella sigue siendo la aprobación o mirada humana. Si para esa aprobacion además tenés la fricción propia de muchas pestañas abiertas, se complica aun más.
Cómo trabajo con diez terminales
Con la llegada de la IA mi forma de trabajar (y la de miles de developers) cambió: en vez de una sesión de Claude Code larga, corro varias en paralelo, cada una en su worktree de git y con una tarea acotada. Algunas en modo plan (Claude propone, yo apruebo), otras con auto mode para cosas mecánicas.
Funciona, pero tiene un costo: la atención. El trabajo real pasa a ser responder prompts: “¿corro `npm test`?”, “¿apruebo el plan?”, “¿qué base de datos uso?”. Y esas preguntas llegan desordenadas, desde cualquier tab.
Tenía un Stream Deck XL (32 teclas) que usaba como acceso directo a sitios y apps, muy básico. Ahi se me ocurió usarlo para Claude y la primera forma que pensé fue también muy sencilla: una tecla por tab, que me muestre qué está haciendo cada Claude, y tres teclas debajo para responder `1`, `2` o `3` sin cambiar de tab.
Lo que ya existía (y lo que no)
Primer reflejo: buscar si alguien lo hizo. Dentro de la misma app de Stream Deck encontré que el marketplace tenía varios plugins pagos. Como segundo paso fuí a buscar en GitHub. Ahi vi varios repositorios, todos de este año. Algunos muestran el estado de las sesiones, uno aprueba permisos interceptando el hook, varios miden el uso de la suscripción. Ninguno hacía todo lo que yo quería: responder en la sesión correcta de iTerm sin cambiar de foco o expandirse a N numero de sesiones. Por eso, decidí arrancar el mío. (Más tarde vuelvo sobre esto, quizás la revisión fue demasiado rápida).
El primer descubrimiento: iTerm2 ya sabe todo
Le pedí a Claude Code que investigara antes de escribir una línea. En veinte minutos apareció lo importante:
iTerm2 3.7 ya integra Claude Code. Es una funcionalidad de la ultima version. Ese puntito de colores en la tab lo pone un binario llamado cc-status que iTerm registra como hook en `~/.claude/settings.json`. Lo malo: iTerm guarda ese estado pero no lo expone para consultarlo desde afuera.
iTerm2 trae un CLI escondido. En `/Applications/iTerm.app/Contents/Resources/utilities/` hay un binario `it2` que habla con la Python API:
it2 session list - json # todas las sesiones con id, tab, tty
it2 session focus <id> # enfocar un pane
it2 session send "1" - session <id> # mandar texto SIN cambiar de tabEse último comando es toda la idea del proyecto. Si puedo mandarle un `1` a la sesión que está esperando, no necesito ir a mirarla.
Los hooks heredan `ITERM_SESSION_ID`. Claude Code corre dentro de la shell de iTerm, así que cualquier hook que dispara tiene en su entorno el UUID de la sesión de iTerm. Con eso puedo mapear “este evento de Claude” a “esta tab”.
La arquitectura (que entra en menos que un viejo tweet de 140 caracteres)
Un archivo json y un plugin de Stream Deck que los lee. Por un lado, un hook bash de 90 líneas que en cada evento de Claude Code escribe un JSON por sesión:
{
"iterm_session_id": "DF3BD86C-…",
"status": "waiting",
"kind": "permission",
"detail": "$ npm test - watch",
"suggestion": "Bash(npm test:*)",
"permission_mode": "plan",
"agents": 2
}Por el otro, un plugin de Stream Deck (Node, el SDK oficial de Elgato es open source) que mira esa carpeta, cruza con `it2 session list` y pinta las teclas. Sin servidores HTTP, sin puertos, sin permisos de Accesibilidad. Los archivos son la API.
Las cuatro veces que se rompió
Acá está lo que más me interesa contar, porque es cómo trabajo con IA: el primer build tardó 10 minutos, y los siguientes 50 fueron corregir cosas que sólo aparecen usándolo.
A. Veo 5 columnas pero tengo 7 tabs. El plugin sólo mostraba sesiones que ya habían disparado algún hook. Las que estaban quietas desde antes de instalarlo no existían. Solución: detectar sesiones por proceso, `ps -axo pid,tty,comm` filtrando `claude`. Si hay un proceso en la tty de esa tab, hay un Claude ahí, haya hooks o no.
B. Las tabs 3 y 4 me salen idle y están trabajando. No eran tabs: eran dos *panes* con teammates de agent teams dentro de la tab 2, que no imprimen nada. Yo generaba una columna por pane. Pasé a una columna por tab, usando el primer pane con Claude.
Get Pablo M. J. Alaniz’s stories in your inbox
Join Medium for free to get updates from this writer.
C. Authentication failed desde el plugin. it2 funciona sin más desde una shell de iTerm, pero el plugin es hijo del proceso de Stream Deck. Hay que pedirle una cookie a iTerm por AppleScript:
tell application "iTerm2" to request cookie and key for app named "Claude iTerm Deck"Y esa cookie es de un solo uso. Para una reutilizable hay que agregar `reusable true`, y entonces iTerm muestra un banner pidiéndole al usuario que apruebe. Terminé con las dos: intento la reutilizable al arrancar, y mientras tanto uso una por llamada (0,3 s, tolerable).
D. Los nombres cambiaban solos. Usaba el basename del cwd del hook como nombre de la sesión, y el cwd cambia cada vez que Claude hace ‘cd’ en un comando. Terminé usando el nombre que Claude Code le pone a la sesión.
Cada una de estos errores fue un mensaje mío de una línea (“El tab 3 me sale idle cuando está working”) y una iteración de Claude Code leyendo logs, probando en mi máquina y corrigiendo. Ese ciclo — yo uso, cuento lo que veo, el agente diagnostica — es más rápido que cualquier spec que hubiera podido escribir de antemano.
Cherry picks: cinco agentes leyendo repos ajenos
Cuando el plugin ya funcionaba, hice lo que quizás debería haber hecho al principio: lancé cinco agentes Opus en paralelo, uno por repo del nicho, con la consigna de clonar, leer el código (no el README) y devolver qué valía la pena adoptar, qué no y por qué.
Volvieron con varias incorporaciones útiles: el archivo de sesiones de Claude Code, los eventos de hooks que no registraba (`SubagentStart`, `PostToolUseFailure`, `PermissionDenied`…), el endpoint de uso que usa `/usage` de la CLI, la idea del long-press para desatascar una tecla.
Entonces resulta que sí había valor en los repos. Mi síntesis inicial, cuando claude los analizó, lo hizo muy superficial. El primer informe decía cosas como “abandonado” y “tiles zombies” sobre proyectos de gente que liberó su código gratis y con funcionalidades buenas. Por eso, antes de publicar el mio, armé un documento de prior art que acredita cada idea que tomé.
Vistas: el deck se adapta a cuántas sesiones tenés
Lo último que agregué es lo que ningún plugin del nicho resuelve: qué pasa cuando tenés más (o menos) sesiones que teclas. El plugin empaqueta tres perfiles. Un perfil en Stream Deck te permite cambiar todo el layout rápidamente. Ahi arme 3 modos:
- Focos (1–3 sesiones): dos columnas por sesión, con modelo, modo, costo estimado y Esc/Enter propios.
- Standard (4–7): una columna por tab. Es el que uso en la diaria
- Denso(8–14): dos filas de sesiones y una fila de respuestas que actúa sobre la sesión seleccionada.
Lo que aprendí
- El plan importa. Veinte minutos de exploración antes que tocar una linea de código (qué hace `cc-status`, qué expone `it2`) definieron toda la arquitectura. Sin eso hubiera armado un servidor HTTP como los demás.
- El feedback real importa más que la spec. Las cuatro roturas no las hubiera previsto. Usar la herramienta de verdad, con mis diez sesiones reales, y describir lo que veo fue el loop que funcionó.
- Los agentes en paralelo te ayudan a investigar. Cinco Opus leyendo cinco repos en 10 minutos es algo que yo solo no hago en una semana. Para construir, en cambio, una sola sesión con contexto completo rindió más.
- Cuidado al publicar. Rutas personales en capturas, nombres de proyectos de clientes en los previews, un documento interno con tono muy interno. Todo eso hubo que sacarlo antes de subir el repositorio publico
- El cuello de botella sigo siendo yo. Y está bien. El deck no decide por mí; me deja decidir más rápido y sin perder el hilo de lo que estaba haciendo.
Para probar
Necesitás macOS, iTerm2 ≥ 3.7 con la Python API habilitada, la app de Stream Deck y `jq`:
git clone https://github.com/PabloAlaniz/claude-iterm-deck && cd claude-iterm-deck
hooks/install.sh
cd plugin && npm install && npm run build && npm run profiles
npx streamdeck link com.pabloalaniz.claude-iterm-deck.sdPluginSi tenés un Stream Deck de otro tamaño, hay perfiles generados para Mini, MK.2, Neo y + (sin probar en hardware: si tenés uno, contame qué pasa).
Links
- El repo: PabloAlaniz/claude-iterm-deck
- Prior art y qué tomé de cada proyecto: `docs/prior-art.md`
- Integración de Claude Code en iTerm2
¿Trabajás con varias sesiones de Claude Code a la vez? ¿Cómo manejás los prompts? Contame en los comentarios, y si algo falla al instalarlo (Automatización, cookie de iTerm, keychain), comentá acá y lo resolvemos.










