B10 ship
Orquestador del pipeline issue -> worktree cerrado. ENTRADA DEFAULT para trabajo issue-shaped: cualquier pedido de resolver/trabajar/shipear UN issue ("resuelve el issue N") o de drenar un epic ("procesa el epic N") sin pedir parar en el PR draft rutea aquí. Idempotente: re-correr el mismo comando retoma donde quedó. NO usar si piden explícitamente parar en el PR draft (eso es b7-issue-to-pr) ni para un cluster de issues relacionadas en un solo PR (eso es b8-swarm).From its SKILL.md
npx -y skills add jporre/sveltekit-verticalslices --skill b10-shipAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 6 stars6 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
12.3 KB, as published. Nobody here has run it
b10-ship — issue → worktree cerrado
SIN
context: forka propósito: este skill corre en el main loop porque necesita el toolWorkflow(no existe en forks) yAskUserQuestioncon el usuario presente. La aislación la dan los skills encadenados (b7 es fork; los agentes de Workflow son subagentes).
Argumentos
<issue> # modo single-issue
--epic=<N> # modo epic: drena el grafo de sub-issues de N
--dry-run # solo reporta qué haría (reconcile + plan), no ejecuta
--informe # al cerrar, invocar informe-semanal --feature
--cluster # en modo epic: olas independientes vía b8-swarm (1 PR combinado)
El estado canónico vive en GitHub (labels, comentarios con markers, PRs). Recuperación universal: re-correr /b10-ship <mismo arg> — la reconciliación salta a la fase pendiente.
Cadena single-issue
0. Preflight + lock
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(cat "$HOME/.claude/b-pipeline.root" 2>/dev/null || ls -d "$HOME"/.claude/plugins/marketplaces/b-pipeline* 2>/dev/null | head -1)}"
B10="$PLUGIN_ROOT/skills/b10-ship/scripts/run.sh"
bash "$B10" preflight # 20=killswitch, 12=gh auth, 18=tree sucio, 17=backpressure, 19=env-check, 2=script faltante
bash "$B10" acquire-lock # 21=otro run activo (stale a las 6h); emite B10_LOCK_TOKEN
- exit 17 (backpressure, ≥3 PRs auto-pr-bot abiertos): NO abortar a secas.
- Modo epic con
epic-auto-mergevigente (label en el EPIC, actor humano no-bot víabp_label_event— re-verificar en CADA corrida, el humano puede removerlo): auto-drenar. Orden: (1) correracquire-lockANTES de drenar (exit 21 → notificar y parar, JAMÁS drenar sin lock); (2) set drenable = PRsauto-pr-botabiertos cuyo issue es sub-issue del epic Y veredicto b6blockers=0— NUNCA PRs fuera del epic, NUNCAblockers>0, NUNCA el closing_slice; (3) drenar conSkill b-pipeline:b9-close "<PR> --auto-merge --epic=<N>"serial, uno a uno;mergeable != MERGEABLE→ saltar ese PR (queda para humano) y seguir; algún check de CI en FAILURE o merge rechazado por branch protection → cortar el drenaje COMPLETO y notificar (en desatendido FAILURE nunca es "preguntar"); (4) re-correrpreflight; si sigue en 17 (PRs foráneos o saltados sostienen el cap) → caer al caso general de abajo.B7_MAX_OPEN_PRS=3queda intacto como cota de PRs huérfanos. - Caso general: listar los PRs abiertos (
gh pr list --label auto-pr-bot) y ofrecer drenarlos primero (fase close sobre los que tengan aprobación — ver "drain-first"). El propio gate de merge humano es lo que destraba.
- Modo epic con
- exit 18 (working tree del repo principal sucio): reportar los archivos y parar — b7/b8 abortarían igual a mitad de build.
- exit 20/21/12/19: reportar y parar. Tras exit 21 NO correr release-lock — el lock es de otra sesión (puede estar legítimamente retenida en un gate humano).
- Guardar
B10_LOCK_TOKENy liberar al terminar conrelease-lock <token>(éxito o falla). El token evita borrar el lock de otra sesión. - TOCTOU residual: b7 re-chequea backpressure y tree limpio en SU preflight; si b7 aborta sin sticky comment, la causa probable es ese preflight (estado cambió entre medio) — re-correr
/b10-ship Nreconcilia y reintenta.
1. Reconciliar
bash "$B10" reconcile <N>
Saltar a la fase que indica B10_PHASE=:
| B10_PHASE | Significado | Acción |
|---|---|---|
done | Issue cerrado | Reportar no-op. Si aparece B10_WORKTREE (limpieza pendiente) o B10_PR_ORPHAN (PR abierto de un issue cerrado), ofrecer resolverlos vía b9. |
close | PR con veredicto b6 blockers=0 (o B10_PR_MERGED: mergeado con issue abierto) | Ir a fase 5 (close). |
verify | PR abierto sin review, o con veredicto blockers>0 | Ir a fase 4 (verify). |
build | Worktree existe sin PR | Retomar build (fase 3). Si B10_ZOMBIE=true: ver "runs zombie". |
blocked | Deps abiertas (B10_BLOCKED_BY) o needs-info sin respuesta | Reportar y parar (en modo epic: seguir con otro issue). |
triage | Nada empezado (o needs-info con respuesta nueva) | Fase 2. |
2. Triage — gate condicional
Fast-path (issues de b0): si el reconcile emitió B10_TRIAGE=ready complexity=<x> scope=<y>, usar ese veredicto DIRECTO — no invocar b1 (haría lo mismo: leer esos labels). El gate complex de abajo aplica igual. Sin el token (issue foráneo, o con comentario humano nuevo):
# vía Skill tool:
Skill b-pipeline:b1-triage-issue "<N> --auto"
Parsear la última línea TRIAGE_RESULT {...}. Fallback si falta: leer labels del issue (ready/needs-info/blocked/duplicate + simple/medium/complex).
verdict=readyy complexitysimple|medium→ fase 3.verdict=readyy complexitycomplex→ GATE: b7 baila con complejidad complex por política propia. ANTES de preguntar, consultar el labelforce-complex-okdel issue:bp_label_event <N> force-complex-okcon actor humano no-bot Ylabeled_atPOSTERIOR al último comentario de triage (## Evaluacion de Issue) = decision "forzar" ya tomada (en modo epic la pone el batch post-triage — ver epic-mode.md) →Skill b-pipeline:b7-issue-to-pr "<N> --lang=es --force-complex"sin re-preguntar. Label de bot o anterior al triage → removerlo (stale) y seguir como si no existiera. Sin label válido: preguntar víaAskUserQuestion: "Issue #N es complex — ¿forzar b7 / construir interactivo (b2) / saltar?". Si elige forzar:Skill b-pipeline:b7-issue-to-pr "<N> --lang=es --force-complex"(b7 soporta el flag; los budgets siguen aplicando). En headless sin label válido: comentar en el issue, no tocar labels, parar.verdict=needs-info|blocked|duplicate|closed→ las preguntas/razones ya quedaron en el issue (las posteó b1). Notificar (PushNotification si está disponible) y parar. Reanudación: cuando el reporter responda, el próximo re-run detecta el comentario nuevo (B10_NEEDS_INFO_ANSWERED=true) y re-triagea solo.
3. Build
Skill b-pipeline:b7-issue-to-pr "<N> --lang=es"
Parsear la última línea B7_DONE issue=<N> pr=<url|none> status=<s>. b7 puede anexar tokens opcionales: lane=<S|M|L> (carril del run; ver b7 paso 1b) y screens=<ok|skipped-<r>|fail|none> (resultado del screen review; none = triage sin screens). Son informativos y el parser tolerante ya los cubre (tokens k=v desconocidos se ignoran) — no cambian el routing de esta fase, pero screens va al reporte final del run. Fallback: bash "$B10" reconcile <N> — si aparece B10_PR, el build terminó.
status=ok→ fase 4.status=needs-human-review→ label ya puesto por b7; notificar y parar (worktree intacto para corrección humana).status=bailed|aborted→ leer la razón del sticky comment del issue; si es budget/no-progress → labelpipeline-failed+ comentario diagnóstico (fase, worktree, último error) y parar.
4. Verify
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(cat "$HOME/.claude/b-pipeline.root" 2>/dev/null || ls -d "$HOME"/.claude/plugins/marketplaces/b-pipeline* 2>/dev/null | head -1)}"
WT=<B10_WORKTREE si existe>
[ -n "$WT" ] && bash "$PLUGIN_ROOT/skills/b1-add-worktree/scripts/assert-clean.sh" "$WT" --fix
# exit 6 -> Skill b-pipeline:b3-git-commit en el worktree + push (el PR debe contener TODO)
Veredicto b6: buscar el marker en comentarios del PR (B10_B6 del reconcile). Si absent:
Skill b-pipeline:b6-pr-review "<PR> --auto"
blockers=0→ fase 5.blockers>0→ b7 ya re-iteró lo que pudo; labelneeds-human-reviewal issue, comentar resumen de blockers, notificar y parar.
5. Close — gate humano SIEMPRE
Skill b-pipeline:b9-close "<PR>"
b9 trae los dos canales de aprobación (label merge-approved asíncrono / AskUserQuestion en sesión) y TODOS los guardrails de limpieza (rescue branch, multi-Closes, no force-remove). No duplicar nada de eso aquí.
- Usuario ausente y sin label → b9 deja
awaiting-approvaly aborta: notificar con URL del PR y parar. El próximo re-run salta directo a esta fase. B9_MERGED→ si se pasó--informe:Skill informe-semanal "--feature <N>". Reportar.
6. Cierre del run
bash "$B10" release-lock "$B10_LOCK_TOKEN" # solo borra si el lock es de esta sesión
Última línea SIEMPRE:
B10_DONE issue=<N> phase_final=<done|stopped-at-*> pr=<url|none>
Modo epic (--epic=<N>)
Leer references/epic-mode.md ANTES de despachar — loop principal, drain-first con snapshot, paralelismo (triage/verify/wave-build), batch de aprobaciones por ola, cap dinámico de backpressure y gate de epic-review viven ahí.
Switch único — modo rápido: si el epic trae epic-auto-merge vigente (actor humano no-bot; lo estampa b0 en el gate o el usuario a mano), el modo rápido se activa COMPLETO sin flags ni env vars: drenaje auto-merge + wave-build (B7_PARALLEL=1 implícito, B10_WAVE_MAX=4) + cluster automático por scope + cap dinámico + review funcional diferido al epic-review (builds con --no-screens --light-review --no-changelog; excepto el closing_slice). Quitar el label del epic apaga todo y vuelve a secuencial+gates. Detalle en epic-mode.md ("Modo rápido").
Runs zombie
reconcile emite B10_ZOMBIE=true si el heartbeat del worktree tiene >2h. También: bash "$B10" janitor lista todos (y se salta el barrido si hay CUALQUIER lock b7 fresco en el state dir — b7.lock o shard b7-issue-<N>.lock con B7_PARALLEL=1; un build corriendo NO es zombie aunque su heartbeat se atrase en fases largas como screen-review esperando login). Nunca barrer con un build potencialmente vivo: si hay duda (laptop suspendida, sesión colgada), preguntar al usuario antes del sweep. Acción del sweep: commit de lo que haya (Skill b-pipeline:b3-git-commit), push de la rama, label pipeline-failed + comentario diagnóstico en el issue (fase, worktree, último error de .b7/iter-*.tail), y recién ahí decidir re-run o escalar.
Reglas
- Solo decidir y encadenar. Cero lógica de build/review/merge propia. Si un skill encadenado falla, NO improvisar su trabajo aquí.
- Gates: solo los definidos en las fases. Nada más frena — no inventar gates nuevos.
- Parser: si la línea machine-readable Y su fallback de labels/markers faltan, parar con diagnóstico — no adivinar.
- Notificar en cada freno (PushNotification si disponible; siempre comentario/label en GitHub) — el usuario debe poder ver POR QUE se detuvo sin leer logs locales.
--dry-run: correr preflight + reconcile en single-issue, oepic-state.shen modo epic (snapshot paralelo completo), reportar el plan de fases (incluida la clasificación closeable/buildable/blocked) y salir sin ejecutar nada.- Una ola por sesión. Cerrada una ola de ≥2 issues (o con screen-review), NO seguir a la siguiente en el mismo contexto: emitir
B10_WAVE_DONE ... next=<comando>y pedir/clear+ re-invocación. El estado vive en GitHub y en.b7/state.json, no en el contexto — ver "Reset de contexto entre olas" enreferences/epic-mode.md. Nunca proponer/compactpara esto. - Cero browser desde el main context. Verificación visual es SIEMPRE
Agent(b-pipeline:b7-screen-review)(usaagent-browserCLI, deja los PNG en disco). Prohibido abrir pantallas con las tools MCP de Chrome desde acá: cada screenshot queda en el contexto de la sesión y se re-lee en cada request hasta el final del epic.