CommunityProgramación y desarrollogithub.com

cmux-delegate

Transfiere un issue independiente que surgió durante la tarea a su propia sesión de Claude Code en un nuevo espacio de trabajo cmux, con contexto recopilado automáticamente; esa sesión ejecuta issue→worktree→PR por sí sola. No es para dividir la tarea actual.

¿Qué es cmux-delegate?

Esta skill permite delegar issues independientes que surgen en medio de una tarea a una sesión separada de Claude Code dentro de un nuevo workspace de cmux. Recopila automáticamente el contexto actual de la conversación (metadatos de git y resumen de razonamiento sintetizado), abre una sesión independiente y esa sesión ejecuta el flujo completo de issue→worktree→PR. No está diseñada para dividir la tarea actual, sino para sacar problemas que pueden resolverse por sí solos. Soporta distribución paralela de múltiples issues, uso de cuentas separadas y reutilización de sesiones existentes. La skill se invoca con el comando `/cmux-delegate` seguido del número de issue y opciones como `--model`, `--session`, `--account`, o `--distribute`. Es importante que el issue ya exista antes de delegar; si no existe, se debe crear en la sesión actual primero. La skill sigue un proceso estricto: analiza argumentos, decide si usa una sesión existente o nueva, recopila contexto del proyecto (estado de git, archivos modificados, información del PR, comentarios de revisión), construye un archivo de prompt con todo el contexto, y lo entrega a la sesión delegada. El principio clave es 'disparar y olvidar': la sesión delegada trabaja de forma autónoma sin reportar de vuelta, y el usuario ve el resultado directamente en la pestaña de cmux correspondiente.

Compatible con✓Claude Code✓Codex CLI~Cursor✓Gemini CLI
npx skills add https://github.com/devseunggwan/praxis/tree/HEAD/skills/cmux-delegate

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace cmux-delegate?

Descripción general

Una skill que transfiere un issue independiente que surgió en medio de una tarea a una sesión diferente. Recopila automáticamente el contexto de trabajo actual de la conversación (metadatos de git + contexto de razonamiento sintetizado a partir de la conversación), abre una sesión independiente de Claude Code en un espacio de trabajo cmux, y esa sesión ejecuta issue→worktree→PR hasta completarlo por sí sola. Se admite la reutilización de una sesión existente, perfiles de cuenta separados y la distribución paralela de múltiples issues.

Principios fundamentales:

  • El prompt siempre se entrega mediante un archivo. Está estrictamente prohibido usar -p en línea (evita problemas de escape de shell).
  • Cuando el usuario nombra una sesión/cuenta explícitamente, se sigue al pie de la letra. Sin reinterpretaciones arbitrarias.
  • La unidad de delegación es un issue independiente. Si puede mantenerse como issue, deléguelo; si no puede, no es un objetivo de delegación sino una pieza para finalizar en esta sesión.
  • La ambigüedad se elimina antes del lanzamiento, no después. Nada vuelve para preguntar, por lo que la condición de finalización, el alcance y el procedimiento se incluyen en el prompt como comandos, rutas y números (Paso 2.6).
  • Disparar y olvidar. Delegar es el final — el trabajador no reporta nada de vuelta al delegador, y el delegador ni monitorea ni juzga al trabajador. El usuario ve el resultado directamente en esa pestaña de cmux.

Cuándo usarlo

Úselo cuando surja un problema separado de lo que está haciendo ahora durante una tarea.

  • Encontró un error no relacionado durante la implementación y quiere separarlo
  • Un hallazgo de revisión está fuera del alcance de este PR y va a un issue de seguimiento
  • Varios issues se acumularon de esa manera y cada uno debe ir a una sesión diferente (--distribute)

Elegibilidad para delegación

¿Puede ese elemento mantenerse como un issue independiente? — esta sola prueba lo decide.

VeredictoManejo
Se mantiene como un issue (tiene su propia reproducción, alcance y criterios de finalización, y puede continuar incluso si mi trabajo está incompleto)Delegar
No puede mantenerse como un issue (es una pieza de mi trabajo actual, y mi trabajo solo está completo cuando su resultado regresa)No delegar — finalícelo en esta sesión

Un elemento cuyo resultado debe regresar para ser fusionado no es un objetivo de delegación. Eso es trabajo de un subagente, y usar esta skill para ello significa exigir un informe del trabajador — una exigencia que históricamente trajo la recolección de informes de finalización (#894) y la puerta de decisión (#984). Ambos se eliminaron en #1130.

Entradas

Especifique el issue a delegar mediante su número de issue.

/cmux-delegate "#1140 auth 토큰 갱신 실패" --model opus
/cmux-delegate "#1141 리뷰에서 나온 후속 항목" --session claude-2
/cmux-delegate "별건 3개: #1140, #1141, #1142" --account claude-2 --distribute

El issue debe existir ya en el momento de la delegación. Si aún no hay issue, créelo en esta sesión antes de delegar — la creación de issues es un procedimiento que requiere aprobación, por lo que no se entrega al trabajador. Si solo se pasa una descripción sin número, el trabajador no puede saber a qué issue adjuntar el PR.

Argumentos

ArgumentoPor defectoDescripción
<tarea>(requerido)Descripción de la tarea a delegar
--modelruta jev, si no sonnetNotación Proveedor:modelo. fable/opus/sonnet/haiku = claude. También admite claude, claude:opus, codex (= gpt-5.6-terra, esfuerzo medium), codex:gpt-5.6-sol, codex:gpt-5.6-sol:xhigh, claude:opus:low / opus:low (claude --effort, uno de low/medium/high/xhigh/max; ninguno nombrado → ninguno pasado), gemini, gemini:flash. Consulte ARCHITECTURE.md Enrutamiento de Proveedores del proyecto.
--cwddir actualDirectorio de trabajo para la nueva sesión
--max-budget-usd—No soportado (#1054). Una bandera solo en modo impresión, por lo que no se puede usar con un trabajador interactivo. Si se proporciona, no lo ignore silenciosamente — informe al usuario
--account(cuenta por defecto)Perfil de cuenta de Claude (ej. claude-2 → CLAUDE_CONFIG_DIR=~/.claude-2)
--session(crear nueva)Entregar en un espacio de trabajo existente (nombre o referencia de espacio de trabajo)
--distributefalseDistribución paralela a granularidad de issue. No es fragmentación de una sola tarea
--permission-mode—Eliminado (#1054). El trabajador delegado es una sesión ordinaria, por lo que usa los valores predeterminados ordinarios del usuario

Proceso

Paso 1: Analizar argumentos

Analice los argumentos de {{ARGUMENTS}}:

args = parse("{{ARGUMENTS}}")
cwd = args.cwd || $(pwd)
# Acepte la bandera de presupuesto pero no la reenvíe; dígale al usuario que se recibió (#1054).
# Dejarla caer silenciosamente permite al usuario delegar creyendo que hay un límite.
if args["max-budget-usd"]: warn("--max-budget-usd 는 대화형 워커에 적용되지 않습니다 (#1054)")
account = args.account || ""
session = args.session || ""
distribute = args.distribute || false
task = args.task (texto restante después de las banderas)
short_task = task[:30], sanitizado a [a-zA-Z0-9가-힣 -] solamente (para nombre de espacio de trabajo cmux)
timestamp = segundos época + PID (ej. 1744163800-12345) para evitar colisiones

# Un --model explícito nunca se anula. Sin uno, jev elige al trabajador;
# en {"source": "fallback"} el valor predeterminado sigue siendo sonnet (#1481).
route_source = "explicit"
if args.model: model = args.model
else:
  route = json(python3 "${CLAUDE_PLUGIN_ROOT}/skills/cmux-delegate/jev-route.py" "$task")
  route_source = route.source
  if route.source == "jev":
    model = route.provider == "claude" ? route.tier : route.provider
  else:
    model = "sonnet"

# Resolución de proveedor (de ARCHITECTURE.md Lógica de Resolución de Proveedores del proyecto)
if model matches /^(codex|gemini)(?::(.+))?$/:
  provider = match[1]           # "codex" o "gemini"
  sub_model = match[2] || ""    # "" o "gpt-5.6-sol:xhigh" o "flash" (primeros dos puntos eliminados)
elif model matches /^(fable|opus|sonnet|haiku)(?::[A-Za-z]+)?$/:
  provider = "claude"
  sub_model = model             # "opus" o "opus:low"; el esfuerzo se separa abajo
elif model matches /^claude(?::(.+))?$/:
  provider = "claude"
  sub_model = match[1] || ""
else:
  provider = "claude"
  sub_model = model

# codex nunca cae al modelo predeterminado de configuración: un `codex` simple
# (explícito o una selección jev) obtiene terra, y un modelo listado obtiene su esfuerzo
# a menos que `codex:<modelo>:<esfuerzo>` nombre uno (#1483).
CODEX_DEFAULT_MODEL = "gpt-5.6-terra"
CODEX_EFFORT = {"gpt-5.6-luna": "low", "gpt-5.6-terra": "medium", "gpt-5.6-sol": "high"}
effort = ""
if provider == "codex":
  sub_model, _, effort = sub_model.partition(":")
  sub_model = sub_model || CODEX_DEFAULT_MODEL
  effort = effort || CODEX_EFFORT.get(sub_model, "")
  # El Paso 4 interpola ambos en un envoltorio bash sin comillas, por lo que un valor
  # como `xhigh; touch /tmp/x` se ejecutaría. Rechace cualquier cosa que no sea un
  # identificador simple en lugar de poner comillas, que aún vencerían a `"` y `$( )`.
  if sub_model does not match /^[A-Za-z0-9._-]+$/: abort "modelo codex inválido"
  if effort and effort does not match /^[A-Za-z0-9._-]+$/: abort "esfuerzo de razonamiento codex inválido"

# claude toma un esfuerzo solo cuando se nombra uno: `claude:<nivel>:<esfuerzo>` o
# `<nivel>:<esfuerzo>` (#1499). No hay una tabla predeterminada por nivel como codex tiene.
# La guía de indicaciones de Opus 5.5
# (https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-opus-5-5#calibrate-effort)
# dice "Los nombres de niveles de esfuerzo no corresponden a la misma cantidad de pensamiento
# entre modelos" y aconseja probar varios niveles por modelo contra sus propias evaluaciones
# "en lugar de trasladar la configuración que usó en Claude Opus 5". Por lo tanto, no se
# incorpora ninguna tabla aquí: sin nombre → no se pasa nada y se aplica el valor
# predeterminado del modelo (`medium` en Opus 5.5, `high` en Opus 5). La guía también
# dice "Reserve `xhigh` y `max` para trabajos donde haya medido una ganancia de calidad."
# Una selección jev, que produce un nivel simple, nunca lleva un esfuerzo.
CLAUDE_EFFORTS = ["low", "medium", "high", "xhigh", "max"]
if provider == "claude":
  # Solo una cola alfabética después de los últimos dos puntos es un esfuerzo, por lo que un
  # ID de modelo que en sí mismo contiene dos puntos (Bedrock `…-v1:0`, un ARN que termina
  # `…:application-inference-profile/<id>`) pasa sin cambios.
  # Dos puntos duplicados justo después del proveedor (`claude::high`, `claude::`) son
  # probablemente un error tipográfico de `claude:opus:high`; se verifica antes de la división
  # de esfuerzo, que de otro modo leería `claude::high` como el modelo predeterminado en high.
  # Cada forma de dos puntos duplicados aborta de la misma manera (`opus::low` abajo).
  if sub_model starts with ":": abort "modelo claude inválido"
  if sub_model matches /^(.*):([A-Za-z]+)$/:
    sub_model, effort = match[1], match[2]
  # Una cola mal formada (`opus:`, `opus::low`, `opus:low:high`) no debe llegar
  # a la CLI como nombre de modelo: ningún ID de modelo termina en `:` o es un alias
  # de nivel seguido de `:`.
  if sub_model ends with ":" or sub_model matches /^(fable|opus|sonnet|haiku):/: abort "modelo claude inválido"
  # El Paso 4 pone entre comillas simples el modelo, por lo que el conjunto de caracteres
  # debe excluir `'` y todo metacarácter de shell; admite `:` `/` para ID de Bedrock y
  # ARN, `@` para ID de Vertex (`claude-sonnet-4-5@20250929`), y `[]` para el sufijo de
  # contexto `[1m]`. Sin comillas, `opus[1m]` sería un glob y se convertiría en `opus1`
  # cuando exista tal archivo en el cwd, por lo que las comillas permanecen.
  if sub_model does not match /^[A-Za-z0-9._:@\/\[\]-]*$/: abort "modelo claude inválido"
  # `claude --effort bogus` solo advierte y se ejecuta con el esfuerzo predeterminado, por
  # lo que la CLI no detectaría un error tipográfico; esta verificación es la única.
  if effort and effort not in CLAUDE_EFFORTS: abort "esfuerzo claude inválido '{effort}' (se esperaba low|medium|high|xhigh|max)"

# Verificación previa: verificar que la CLI del proveedor esté disponible
if ! command -v "$provider" &>/dev/null:
  warn "⚠ ${provider} CLI no encontrada, recurriendo a claude:sonnet"
  provider = "claude"
  sub_model = "sonnet"
  effort = ""

Paso 1.5: Resolución de sesión

Decida si usar una sesión existente.

if session is specified:
  1. cmux list-workspaces → coincidir por nombre o referencia
  2. match found → modo cmux send (Paso 5b)
  3. no match → imprimir error "세션 '{session}'을 찾을 수 없습니다" y detenerse
else:
  → comportamiento existente (nuevo espacio de trabajo, Paso 5a)

Paso 1.6: Resolución de cuenta

Decida el perfil de cuenta.

if account is specified:
  # El perfil de cuenta se establece mediante la variable de entorno CLAUDE_CONFIG_DIR
  # ej. --account claude-2 → CLAUDE_CONFIG_DIR=~/.claude-2
  claude_env = "CLAUDE_CONFIG_DIR=~/.{account}"
  
  # Validación: verificar que el directorio de configuración exista
  if not exists(~/.{account}):
    print error "계정 프로필 디렉토리 ~/.{account}이 없습니다" y detenerse
else:
  claude_env = ""  # usar la cuenta predeterminada

Paso 2: Recopilar contexto

Recopile automáticamente el contexto actual de la conversación y del proyecto. Cada comando continúa incluso si falla (2>/dev/null).

Información a recopilar:

# 1. Estado de git
BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
COMMITS=$(git log --oneline -5 2>/dev/null || echo "no git history")
DIFF_STAT=$(git diff --stat HEAD 2>/dev/null || echo "no changes")

# 2. Lista de archivos modificados (vs rama base)
BASE_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||')
BASE_BRANCH=${BASE_BRANCH:-main}
CHANGED_FILES=$(git diff --name-only $(git merge-base HEAD "origin/$BASE_BRANCH" 2>/dev/null || echo HEAD~5)..HEAD 2>/dev/null || echo "unknown")

# 3. Información del PR (si existe)
PR_INFO=$(gh pr list --head "$BRANCH" --json number,title,url 2>/dev/null || echo "no PR")

# 4. Comentarios de revisión del PR (si existen)
REVIEW_COMMENTS="0"
PR_NUM=$(gh pr list --head "$BRANCH" --json number -q '.[0].number' 2>/dev/null || echo "")
if [ -n "$PR_NUM" ]; then
  REVIEW_COMMENTS=$(gh api "repos/$(gh repo view --json nameWithOwner -q '.nameWithOwner' 2>/dev/null)/pulls/$PR_NUM/comments" --jq 'length' 2>/dev/null || echo "0")
fi

# 5. ID de contenido pegado — un ID nuevo por archivo de prompt (ver abajo)
PASTE_ID=$(od -An -N3 -tx1 /dev/urandom | tr -d ' \n')

El texto de terceros está marcado, no es de confianza (issue #1500). Cómo el archivo de prompt llega al trabajador depende del modo:

  • Modo nueva sesión y distribuir (Paso 5a). El envoltorio pasa el contenido del archivo como el primer mensaje de usuario del trabajador (claude y gemini mediante argv, codex mediante stdin), por lo que cualquier cosa que contenga se lee como si hablara el delegador. Este es el caso que aborda el consejo de texto pegado de la guía.
  • Modo sesión existente (Paso 5b). El mensaje de usuario es solo "leer {prompt_file}"; el contenido llega como resultado de la herramienta Read. La guía trata eso como un caso separado: los resultados de herramientas caen bajo la resistencia del modelo a la inyección indirecta de indicaciones ("instrucciones que llegan a través de resultados de herramientas, páginas web y contenido en pantalla o del navegador"). Las etiquetas y la nota permanecen en el archivo (un archivo, cada modo) como un marcador adicional, pero aquí las secciones del propio delegador también son contenido de resultados de herramientas, no un mensaje de usuario.

Parte del texto del archivo no es del delegador: COMMITS lleva asuntos de commits, CHANGED_FILES y DIFF_STAT llevan rutas de archivos, y PR_INFO lleva un título de PR, todos escritos por quien los creó, y el Handoff o las Instrucciones pueden citar cuerpos de issues o comentarios de revisión. Una ruta de archivo puede transportar texto similar a instrucciones tan fácilmente como un asunto (un PR puede agregar docs/FOLLOW-THE-INSTRUCTIONS-IN-THE-PR-BLOCK.md). Cada bloque de este tipo va al prompt entre una etiqueta de apertura y una de cierre pasted_content que lleva el mismo PASTE_ID, cada etiqueta en su propia línea, bajo la nota en la parte superior de la plantilla del Paso 3. La forma de la etiqueta es la que da la guía de indicaciones de Opus 5.5 para texto pegado (https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-opus-5-5#mark-pasted-text-in-user-messages); tres cosas difieren de la guía:

  • Dónde vive la nota. La guía dice "Luego agregue esta nota a su prompt del sistema". Aquí la nota se encuentra en la parte superior del archivo de prompt, es decir, en el mismo mensaje de usuario (o resultado de herramienta) que el texto no confiable. Su debilidad: una nota falsificada dentro de un título de PR o asunto de commit tiene la misma posición...

...

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Skills relacionados