¿Qué hace Ejecutar un Pipeline?
Estás iniciando o reanudando la ejecución de un pipeline. $1 es el PIPELINE a ejecutar — su carpeta bajo ./.pipeline/. (Un pipeline v1 puede ser nombrado por una ruta de archivo de iteración; consulte Prerrequisitos).
Qué estás haciendo
Eres el supervisor que se ejecuta en la sesión principal (profundidad 0). No iteras sobre las iteraciones tú mismo. En su lugar, creas un único subagente pipeline-manager (profundidad 1) que impulsa toda la cadena — creando un step-executor nuevo por iteración y ejecutando pipeline-improver / pipeline-script-creator entre pasos (el CLI pipeline next que impulsa emite automáticamente los eventos de UI por iteración y ejecuta cualquier hook de worktree externo por sí mismo) — y devuelve un informe estructurado cuando la ejecución se completa, se detiene o encuentra un bloqueador fuera de su alcance.
Debes permanecer en profundidad 0 porque tres cosas deben vivir en la sesión principal y un subagente no puede hacerlas: (a) poseer un pid estable para el archivo de bloqueo de actividad (liveness lockfile) de la ejecución, (b) esperar horas por una condición externa (un PR bloqueador a fusionar) y reanudar, (c) eventualmente presentar los resultados al humano. Por lo tanto, tu trabajo es: generar el id de ejecución (o, con --resume, reingresar a una EXISTENTE — ver "Procedimiento de Reanudación"), configurar el seguimiento de UI, crear el manager y actuar según su informe — incluyendo ejecutar la espera de sondeo del bloqueador anidado y re-invocar al manager para reanudar.
CRÍTICO — disciplina de tokens: leer casi nada
Este skill es un supervisor, no un lector. Cada archivo de iteración es leído por un step-executor en su propio contexto fresco; la resolución de modelo por paso ocurre dentro del pipeline-manager.
- Nunca
Leerun archivo de iteración (steps/**/*.md). Nunca los tocas — ni siquiera su frontmatter. El manager resuelve los modelos por paso; tú solo le pasas el valor por defecto del pipeline. - Lee
PIPELINE.mdsolo como frontmatter (limit: 50), una vez, al inicio de la cadena, para extraer el campomodel:parapipeline_default_modely nada más. No pases su contenido al manager. Con--resume, omita esta lectura por completo —pipeline_default_modelproviene delnext.json.default_modelpersistido de la ejecución existente (ver "Procedimiento de Reanudación"), que es lo que evita que una reanudación agregue una lectura de manifiesto además de la lectura denext.jsonque ya necesita paracurrent_iteration. - Los únicos archivos que puedes
Leercompletamente son los que tú mismo escribes en el flujo de bloqueador anidado (cuerpos de issues, notas de trabajo parcial) y, al reanudar (--resume), los pequeños archivos de cursor de orquestación.runtime/*/next.json— nunca un archivo de iteración o el cuerpo dePIPELINE.md.
Selección de ejecutor (runner, experimental)
Existen cuatro modos, y pipeline next decide qué se ejecuta a continuación en todos ellos (E1) — nunca el bucle que lo llama. Solo difieren en dónde vive el bucle y qué ejecuta un paso:
| Modo | Bucle vive en | Ejecuta un paso |
|---|---|---|
session | esta sesión principal | la herramienta Agent, en sesión |
manager (por defecto) | un subagente pipeline-manager | la herramienta Agent, en sesión |
driver | un proceso que posee este plugin, sin modelo en el bucle (pipeline drive) | un proceso claude -p nuevo por paso |
standalone | el mismo proceso que driver | el SDK de Agent con tu propia clave API — sin sesión de Claude Code en absoluto |
driver y standalone son fáciles de confundir porque comparten un bucle y solo difieren en el ejecutor; no confundas ninguno con pipeline drive, que es el nombre del comando para la ruta driver, no un sinónimo del modo. Este CLI empaquetado implementa session, manager y driver — los pipelines v1 escriben driver como runner: headless en el frontmatter de PIPELINE.md (ver más abajo); standalone y una clave runner: a nivel de pipeline.yml pertenecen al mismo diseño de cuatro modos pero aún no están conectados a esta copia empaquetada, así que no le digas a un usuario que ninguno se ejecutará hoy.
Resuelve runner: junto con la lectura de model: en el paso 3 del Procedimiento. En un pipeline v2 es una clave de nivel superior en pipeline.yml — Grep ^runner: allí, que lee una línea y nunca abre un archivo de paso; en v1 está en el frontmatter de PIPELINE.md, ya dentro de las ≤50 líneas que lees para model:. Ausente o ilegible ⇒ manager, el comportamiento actual y el valor predeterminado deliberado (E10). Un valor que está declarado pero no tiene una rama debajo aún ejecuta manager — pero dilo en una línea antes de comenzar, porque un modo que el manifiesto no declaró es un modo que el autor no eligió. Nunca infieras el modo a partir de la longitud de la cadena: un umbral invisible hace que un comando se comporte de dos maneras.
runner: session — la sesión principal ejecuta el bucle ella misma
NO crees un pipeline-manager. Lee el bucle de sesión y síguelo en lugar de los pasos 5.1–5.3 del Procedimiento; todo lo demás en este archivo — pasos 1–4, el Procedimiento de Reanudación, el Flujo de Bloqueador Anidado, las invariantes del Supervisor y el formato del Informe — se aplican a ti sin cambios, porque sigues siendo el supervisor en profundidad 0 y solo has absorbido el bucle en lugar de delegarlo.
Ese archivo contiene las dos negativas previas al vuelo que este modo necesita (un CLI demasiado antiguo para pipeline next --brief-file, y execution: parallel, cuyas cargas útiles viven en un resumen que la sesión no puede abrir) y es honesto sobre la compensación: cada acción y cada informe de paso aterriza en el contexto que el usuario está viendo, por lo que una cadena larga pertenece a manager — que es precisamente por qué manager sigue siendo el valor predeterminado.
runner: headless (v1) — el modo driver
Cuando el pipeline es v1 y el frontmatter de PIPELINE.md que lees para model: también contiene runner: headless (la forma de v1 del modo driver — ver la tabla anterior), NO crees un pipeline-manager. En su lugar, ejecuta el controlador empaquetado como un proceso en segundo plano y supervisa:
bun "${CLAUDE_PLUGIN_ROOT}/apps/pipeline-cli/src/cli.ts" drive \
--root "<pipeline_root>" --run-id "<run_id>" [--start "<step-name>"] \
--default-model "<pipeline_default_model-or-null>" \
[--default-effort "<level-or-null>"] \
[--model "<step_id>=<model>" ...] [--effort "<step_id>=<level>" ...] --json [--resume]
Lánzalo con run_in_background: true y actúa sobre su JSON final cuando termine: salida 0 → emite pipeline.completed; salida 1 → emite pipeline.halted y muestra el motivo; salida 3 (blocked) → ejecuta el flujo de bloqueador anidado a continuación, luego vuelve a ejecutar drive con --resume. Todo lo demás sobre tu rol de supervisor (id de ejecución, actividad (liveness), enlace de espejo, informes al humano) no cambia. Esta ruta driver (v1: runner: headless) omite las acciones de auto-mejora y deja intacto .feedback/<run_id>/ — menciónalo en tu informe final para que el usuario pueda ejecutar un pase manual del mejorador (improver). Cuando runner: está ausente o es manager, procede exactamente como se indica a continuación.
Selección de modelo
Un pipeline (y cada iteración) puede optar por un modelo de Claude a través del campo OPCIONAL model: en el frontmatter. El campo por defecto se hereda — omítelo y el step-executor hereda el modelo de la sesión. Tú resuelves solo el valor por defecto a nivel de pipeline y lo entregas al manager; el CLI pipeline next resuelve el modelo efectivo por iteración (anulación por ejecución ?? step.model ?? pipeline_default_model) y el manager lo pasa a cada step-executor a través del parámetro model por llamada de la herramienta Agent. Pasa el valor resuelto sin cambios — NO traduzcas un alias a un id canónico. El parámetro model de Agent acepta los alias, ids canónicos e inherit directamente.
Vocabulario aceptado de model: (extremo a extremo): uno de los alias haiku / sonnet / opus / fable, O cualquier id de modelo canónico exacto de Claude (una cadena que comienza con claude-, ej. claude-opus-4-8, claude-sonnet-4-6, claude-fable-5), O inherit / ausente (→ sesión por defecto).
Resuelve pipeline_default_model: en un pipeline v2 el CLI lee defaults.model de pipeline.yml por sí mismo — pasa null y déjalo hacer. De lo contrario, si <pipeline-root>/PIPELINE.md existe, Lee con limit: 50 y toma el valor model: del frontmatter cuando sea un valor aceptado (un alias, un id claude-*, se mantiene textual); inherit/ausente → null. Si PIPELINE.md está ausente, null. Valores inválidos — cualquier cosa que no sea uno de los alias aceptados, un id claude-*, inherit o ausente — advierte una vez y cae a null (no te detengas). (Leer ≤ ~10 líneas de frontmatter es extracción de metadatos, no lectura de contenido — nunca duplica lo que carga el step-executor).
Anulaciones de paso por ejecución (step_model_overrides): el usuario puede fijar pasos individuales a un modelo diferente SOLO PARA ESTA EJECUCIÓN — sin editar ningún archivo de pipeline — ya sea con banderas explícitas después de la ruta (--model <step_id>=<model>, repetible) o en lenguaje natural ("ejecuta los pasos 02-implement y 03-refine en fable"). Normaliza lo que hayan dicho en pares <step_id>=<model>: step_id es el step_id del frontmatter del paso o su nombre de archivo (ej. 02-implement para steps/02-implement.md); model usa el vocabulario aceptado anteriormente (inherit fuerza la sesión por defecto para ese paso). NO lees ningún archivo de paso para validar los ids — el CLI advierte sobre ids desconocidos y rechaza modelos inválidos. Pasa los pares al manager como step_model_overrides (ver 5.1) o, en la ruta driver, como banderas --model repetidas en el comando drive. Una anulación vence al propio model: del paso en el frontmatter; los pasos sin anulación no se modifican. El CLI persiste las anulaciones en el estado de la ejecución al inicio, por lo que las reanudaciones las mantienen automáticamente — vuelve a pasar los mismos pares al re-invocar al manager de todos modos (es inofensivo y sobrevive a un .runtime/ eliminado). Sin anulaciones mencionadas ⇒ omite por completo.
Selección de esfuerzo (esfuerzo de razonamiento — el gemelo de model:)
Un pipeline y cada iteración también pueden optar por un esfuerzo de razonamiento a través del campo OPCIONAL effort: en el frontmatter (niveles: low / medium / high / xhigh / max; inherit/ausente → el esfuerzo de la sesión). Se resuelve a través de la misma escalera exacta que el modelo — anulación por ejecución ?? effort: del paso ?? effort: del pipeline ?? heredado — completamente dentro del CLI pipeline next. Resuelve pipeline_default_effort de la misma lectura de frontmatter de PIPELINE.md que ya haces para model: (misma regla de valor inválido: advierte una vez, cae a null), entrégaselo al manager como pipeline_default_effort, y normaliza solicitudes de usuario como "ejecuta 03-refine con esfuerzo máximo" en pares step_effort_overrides (<step_id>=<level>) pasados exactamente como los pares de modelo (banderas --effort en la ruta driver). NOTA DE HONESTIDAD: el ejecutor driver aplica el esfuerzo de verdad (claude --effort por cada creación); en el modo manager, la herramienta Agent puede que no exponga un parámetro de esfuerzo por llamada todavía — el manager lo pasa cuando es compatible y, de lo contrario, el paso hereda el esfuerzo de la sesión (ver pipeline-manager.md § run-step).
Prerrequisitos
- Un pipeline existe bajo el directorio
./.pipeline/del proyecto actual (típicamente creado con/pipeline:design). $1es la CARPETA del pipeline bajo./.pipeline/(ej../.pipeline/ship-feature), que inicia una ejecución NUEVA — esto siempre genera un NUEVOrun_id.--start <step-name>inicia esa ejecución nueva en un paso nombrado en lugar del primero del manifiesto. Una ruta de archivo de iteración también se acepta, y es cómo un pipeline v1 nombra un paso de inicio. O--resume [<run_id>]para reingresar a una ejecución EXISTENTE bajo surun_idORIGINAL (ver "Procedimiento de Reanudación") — la única forma de continuar la ejecución de una sesión muerta sin huérfanos de estado.- El directorio de trabajo actual es la raíz del proyecto consumidor — todas las ediciones de archivo realizadas por las iteraciones aterrizan aquí.
Emisiones de eventos de Diario (Journal)
Emitir los eventos del ciclo de vida a nivel de ejecución a <project>/.pipeline/.runtime/events.jsonl; los eventos por iteración (iteration.*, improver.*, script_creator.*, worktree.*) son emitidos automáticamente en proceso por el CLI pipeline next que impulsa el manager (el manager mismo emite solo los eventos del mejorador/script de la retrospectiva). Debido a que toda la ejecución comparte un session_id, el enlace de espejo que registras a continuación es lo que permite al hook de análisis correlacionar las llamadas a herramientas del manager y los ejecutores de paso con esta ejecución. Las emisiones son de mejor esfuerzo — nunca dejes que un error detenga la ejecución.
Configuración única al inicio del Procedimiento: genera el id de ejecución llamando al CLI — nunca generes uno tú mismo ni inventes un formato: bun "${CLAUDE_PLUGIN_ROOT}/apps/pipeline-cli/src/cli.ts" id. Captura el valor literal que imprime (un UUIDv7, ej. 019fc762-5762-7000-a9bf-922ed8fa00be).
CRÍTICO — pasa run_id literalmente en cada llamada al escritor. La herramienta Bash de Claude Code no preserva el estado del shell entre invocaciones, por lo que una variable de entorno exportada no alcanza la siguiente llamada a pipeline event. Pasa run_id=<el-id-literal> como un argumento k=v en CADA llamada. Los argumentos k=v no tienen espacios alrededor de =; usa comillas simples para un valor que contenga espacios.
Ayudante de emisión (ejecuta con Bun, silencioso en éxito, sale con 0 incluso en fallo — no verifiques la salida):
bun "${CLAUDE_PLUGIN_ROOT}/apps/pipeline-cli/src/cli.ts" event <tipo-evento> run_id=<id-literal> [k=v ...]
Qué emites (una llamada por viñeta):
-
Con
--resume, esta lista completa no aplica — el Procedimiento de Reanudación emite solowrite-liveness+register-mirror-bindingpara elrun_idEXISTENTE, y nuncapipeline.started(reingresar a una ejecución no es iniciar una). Ver "Procedimiento de Reanudación". -
Después del banner:
pipeline.started run_id=<id> pipeline_name=<nombre> first_iteration_path=<absoluto> pipeline_root=<absoluto> default_model=<modelo-o-null>—default_modelespipeline_default_model(un aliashaiku/sonnet/opus/fable, un id canónicoclaude-*, o el literalnull). -
Inmediatamente después de
pipeline.started, escribe el archivo de bloqueo de actividad (liveness lockfile) para que un lector pueda saber que esta ejecución murió sin un evento terminal:bun "${CLAUDE_PLUGIN_ROOT}/apps/pipeline-cli/src/cli.ts" event write-liveness run_id=<id> pid=$PPID(PowerShell:pid=$PID). Pasa el pid del SO del proceso que impulsa este supervisor —$PPIDes el mejor identificador portátil para la sesión persistente de Claude. El daemon solo retira automáticamente una ejecución cuando este pid es un proceso real y muerto, por lo que un valor poco confiable es un no-op seguro. -
Im
...
[truncado para traducción]