Bus y ask

Mensajes de una vía entre sesiones, y la pregunta bloqueante que levanta un worker cuando la decisión no es suya.

En palabras simples#

Dos escritorios, misma oficina. Una nota es un post-it en el otro escritorio (“cambió el formato de la etiqueta — vuelve a revisar”). Un ask es levantar la mano y esperar (“¿cuál campo es el canónico?”) para que nadie invente la respuesta en silencio.

Le hablas a tu Chair en lenguaje normal. El Chair entrega la nota o la mano alzada. Para el día a día no necesitas los nombres de herramientas de abajo — están para quien opera y quiere los verbos exactos.

Los asientos corren en CLIs y modelos distintos y comparten un solo bus: un asiento le escribe a otro por nombre, no por proveedor. Los cuerpos viajan en modo contexto, así que un mensaje cuesta una línea y un id en la ventana de quien lo lee. Lo que gastó cada asiento está en /app/board.

Qué es#

Dos formas de que las sesiones se hablen, y no son intercambiables.

El bus es de una vía. msg_send necesita un cuerpo, una identidad (from_session / from_agent) y un destino. Elige el destino según lo que sepas:

Argumento de destino Alcanza a
to_session y/o to_agent Ese asiento exacto
to_worker Un id de worker: estable entre recogidas y relanzamientos, a diferencia del id de sesión
to_role parent (el Chair; chair se acepta y significa lo mismo), child o sibling. Los siblings y children de un mismo Chair se encuentran entre proyectos del workspace. Si no hay asiento de Chair en el roster, chair/parent igual entrega, dirigido al rol — el msg_inbox {} del Chair lee su asiento y el rol.
to_project Un id de proyecto registrado: el Chair en curso de ese proyecto

Los cuerpos son telegráficos; kind suele ser note, handoff o alert. El resto del bus son msg_inbox, msg_ack, msg_stale (alertas que nadie levantó), msg_peers y msg_roster. Los humanos tienen los mismos verbos bajo orch msg.

Todo mensaje nombra a su autor: <nombre visible> (<id de agente>/<preset o CLI>) via orch <id de sesión>. msg_inbox lo lleva como un campo From ya renderizado junto al FromSession/FromAgent crudo — la misma convención cubre ask/ask_answer, las filas de lock y task_list, así que quien lea cualquiera de ellos sabe siempre qué asiento hizo qué y por cuál CLI.

Un ask bloquea. Cuando la decisión no es tuya y no puedes seguir sin ella, levantas uno en vez de adivinar:

ask { question, options?, context?, timeout_sec?, to_session?, to_project? }

Se sostiene hasta que alguien responda o venza el tiempo — timeout_sec es 600 por defecto. Cuando se dan options[], esas cadenas son una pista, no un filtro: un índice base 1 o una coincidencia sin distinguir mayúsculas elige una, y cualquier otro texto se registra tal cual como respuesta. Una respuesta numérica que coincide con el índice de una opción se mapea a esa opción; antepón = (por ejemplo =2) para forzar el texto literal. La primera respuesta gana y una segunda recibe un rechazo claro.

Levantar un ask también deja un alert en la bandeja del Chair nombrando el id y pasa por el fan-out de notificaciones configurado. El Chair puede notarlo en msg_inbox, pero responde con ask_answer — o lo hace un humano, desde una terminal:

orch ask list
orch ask answer <id> --answer "…"

La respuesta a un "¿cómo resolviste X?" entre proyectos puede llevar un symbol_ref — {project, path, line, symbol} — en lugar de un cuerpo pegado. Orchemax lo valida contra el índice antes de aceptarlo: el símbolo tiene que resolver bajo ese proyecto y ser de alcance shared. Quien preguntó obtiene el texto con code_snippet.

Por qué existe#

Porque "el agente se quedó callado" y "el agente decidió por su cuenta" son ambos fallas, y un mensaje de una vía no las distingue. Un ask vuelve explícita la espera y, más importante, vuelve explícito el timeout: el silencio no es un estado en el que Orchemax te vaya a dejar.

worker ---- ask -----> Chair            el worker bloquea
worker <- respuesta -- Chair            la primera respuesta gana
worker <-- timeout ---  (nadie)         fila marcada "timeout", el error nombra la pregunta

Un ask vencido queda registrado, no tragado: el estado de la fila pasa a timeout, la herramienta devuelve un error que nombra la pregunta, y a un Chair que responde tarde se le avisa que llegó tarde. El worker decide entonces por su cuenta — y lo dice en verify_report.

Cómo se relaciona con el resto#

  • Solo el Chair puede lanzar. Un worker que necesita más manos le escribe al Chair con to_role=parent; no hace fan-out. Ver Chair y workers.
  • Los agentes se coordinan únicamente por este bus. Sockets de proveedor y chats paralelos quedan fuera: un bus paralelo es invisible para el board, el roster y el recolector.
  • Un mensaje handoff con el veredicto de una línea es parte de cómo reporta una sesión cerrada, junto con el board y la página de sesión.

Aquí no hay nada que ejecutar#

Los verbos existen bajo orch msg y orch ask para un humano en una terminal, pero el camino normal es un agente llamando a la herramienta MCP. Lo más probable es que te encuentres con el bus como un orch ask list cuando un worker te está esperando.