name: wf-new description: Starts a new SDD need via the waterfall workflow — agent teams preflight, TeamCreate, OR spawn, bootstrap_need. user-invocable: false allowed-tools: Read, Write, Grep, Glob, Bash(bash *, git *), AskUserQuestion, Skill
wf-new — Bootstrap a new need
This skill is the entry point of the waterfall workflow for a new need. It is invoked by the /waterfall:new slash command. Its sole role: prepare the environment, resolve the name, and hand off to OR.
Flow Z — Bootstrap Agent Teams
Step 1 — Preflight
bash ${CLAUDE_PLUGIN_ROOT}/scripts/wf-check-bash.sh
If exit ≠ 0: display the error to HO and stop. The plugin requires bash (Git Bash on Windows).
bash ${CLAUDE_PLUGIN_ROOT}/scripts/wf-check-teams.sh
If exit ≠ 0: display the error to HO and stop. The flag CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 is required (see README.md Prerequisites).
Step 1.bis — jq verification
jq is used by all wf scripts to parse .wf-state.json, ack-registry.json, etc.
INSTALL_CMD=$(bash ${CLAUDE_PLUGIN_ROOT}/scripts/wf-check-jq.sh) || JQ_RC=$?
- Exit 0 → continue.
- Exit 2 →
jqmissing.$INSTALL_CMDcontains the install command adapted to the detected OS (empty if no known package manager).- If
INSTALL_CMDnon-empty →AskUserQuestion: "jq is required. Install it now via${INSTALL_CMD}?" (Yes / No).- Yes →
bash -c "$INSTALL_CMD"then re-runwf-check-jq.sh. If still missing → display stderr and stop. - No → display the command to HO for manual install and stop.
- Yes →
- If
INSTALL_CMDempty → display stderr (manual instructions + URL) and stop.
- If
Step 2 — Name resolution
The name is resolved by PM (main conversation) before any spawn — PM has the fresh verbal context from HO.
- If
$ARGUMENTSprovided → validate kebab-case, use directly as<name> - If
$ARGUMENTSempty: a.AskUserQuestion(open question): "Describe your need in a few words." b. Generate 3 kebab-case proposals (2-4 words, semantically relevant) c.AskUserQuestionwith the 3 options (HO can also enter a free-form name) d. Validate the chosen name: strict kebab-case - Check non-collision:
ls wf/needs/<name>/→ if it exists, AskUserQuestion to confirm overwrite or pick another name
Rule: one question at a time to HO.
Step 2.bis — Config read + validation
source ${CLAUDE_PLUGIN_ROOT}/scripts/wf-read-config.sh || {
echo "Invalid config — bootstrap stopped. Fix .wf-config.json or re-run /waterfall:config."
exit 2
}
The script emits a markdown summary of the resolved config on stdout (visible in the tool result) and exits 2 if a value is invalid. On error: display the summary to HO and stop the bootstrap.
# Copy templates by language (WF_LANGUAGE auto-detected from $LANG by wf-read-config.sh)
TEMPLATES_SRC="${CLAUDE_PLUGIN_ROOT}/wf/templates/${WF_LANGUAGE}"
[[ ! -d "$TEMPLATES_SRC" ]] && TEMPLATES_SRC="${CLAUDE_PLUGIN_ROOT}/wf/templates/en"
cp "$TEMPLATES_SRC"/*.md "wf/needs/<name>/"
Step 3 — Load wf-pm (conditional on agent_mode)
IF WF_AGENT_MODE == "subagent-light":
→ Load wf-pm-light via Skill({name: "waterfall:wf-pm-light"})
→ The main conversation adopts PM-light responsibilities
→ Skip directly to Step 4.ter (no TeamCreate, no pré-spawn)
ELSE:
→ Load wf-pm via Skill({name: "wf-pm"})
→ Continue to Step 4
Step 4 — TeamCreate (conditional on agent_mode)
if [[ "$WF_AGENT_MODE" == "team" ]]; then
# Default mode
TeamCreate wf-<name>
elif [[ "$WF_AGENT_MODE" == "subagent-light" ]]; then
# subagent-light: no TeamCreate, no team, no inter-agent watchdog
# Inform HO: "Subagent-light mode active — 2 agents (PM+TL), 3 artefacts, 3 interactions HO"
: # no-op — proceed to Step 4.ter
else
# Subagent mode (ADR-006): no TeamCreate, agents are spawned via Agent tool
# Inform HO: "Subagent mode active — SendMessage and inter-agent watchdog disabled"
fi
One single team per Claude Code session (platform constraint). If a wf-* team already exists, escalate to HO before continuing.
Step 4.bis — Init .team-registry.json (traceability, optional)
PM may initialize the traceability registry:
mkdir -p wf/needs/<name>
bash ${CLAUDE_PLUGIN_ROOT}/scripts/wf-registry.sh init <name>
DEC-001: this registry is traceability only — the
wf-auth.shhook readsagent_typefrom the harness payload directly. Init is no longer a prerequisite to--completeenforcement.
Step 4.ter — wf-orchestrate.sh --init (PM, AVANT tout spawn) — EX-005 / B3
PM exécute
--initAVANT le spawn d'OR (ou TL en mode subagent-light). Au moment où l'agent reçoit son brief,.wf-state.jsonexiste déjà.
# Mode team / subagent
bash ${CLAUDE_PLUGIN_ROOT}/scripts/wf-orchestrate.sh <name> \
--init --team wf-<name> --session "${CLAUDE_SESSION_ID}" \
--agent-mode "${WF_AGENT_MODE}" --dark-factory "${WF_DARK_FACTORY}"
# Mode subagent-light — pas de team, R-002 résolu : handle_init accepte toute valeur --team
bash ${CLAUDE_PLUGIN_ROOT}/scripts/wf-orchestrate.sh <name> \
--init --team "none" --session "${CLAUDE_SESSION_ID}" \
--agent-mode "subagent-light" --dark-factory "${WF_DARK_FACTORY}"
Propagation config (fix bug-3eec8bce) : les flags
--agent-modeet--dark-factoryoverrident les valeurs lues parhandle_initdepuis.wf-config.json. Source de vérité = les env vars résolues au Step 2.bis parwf-read-config.sh, pas le fichier projet (qui peut être absent).
Idempotence (TF-021) — si .wf-state.json existe déjà :
- soit le script renvoie exit 0 idempotent (no-op)
- soit exit 1 avec message clair désignant l'état existant
- dans les deux cas :
.wf-state.jsonn'est pas corrompu, aucun artéfact métier modifié.
Critère opposable (TF-010) : après cette étape, wf/needs/<name>/.wf-state.json
existe et contient phase, step, session_id non nul.
Step 4.quater — Pré-complete des steps BOOTSTRAP pm-owned (subagent + subagent-light)
Subagent et subagent-light. En mode team, ces 2 steps sont complétés par le PM teammate après que OR ait émis
PLEASE_COMPLETE_STEP. En mode subagent/subagent-light, PM = main agent (hors team), donc OR ne peut pas le contacter viaSendMessage→ deadlock au BOOTSTRAP. PM doit donc pré-compléter ces steps avant le spawn de l'agent suivant (OR en subagent, TL en subagent-light).
if [[ "$WF_AGENT_MODE" == "subagent" || "$WF_AGENT_MODE" == "subagent-light" ]]; then
bash ${CLAUDE_PLUGIN_ROOT}/scripts/wf-orchestrate.sh <name> --complete BOOTSTRAP:DETERMINE_NAME
bash ${CLAUDE_PLUGIN_ROOT}/scripts/wf-orchestrate.sh <name> --complete BOOTSTRAP:RUN_BOOTSTRAP
fi
En mode subagent : après ces 2 --complete, le state machine arrive à
BOOTSTRAP:COLLECT_CARD_NUM (agent=or). OR pilote à partir de là.
En mode subagent-light : après ces 2 --complete, _wf_auto_skip_light
skip automatiquement tous les steps agent=or (COLLECT_CARD_NUM, COLLECT_BRANCH_TYPE,
CREATE_BRANCH_Q, SPAWN_TEAM) jusqu'au premier step agent=pm ou agent=tl.
PM-light pilote directement sans OR intermédiaire.
Step 5 — Pré-spawn batch de la team fixe (EX-002 / F3) — non applicable en subagent-light
subagent-light : pas de pré-spawn. PM-light spawne TL directement lors de la Phase D (après validation specs HO). Aucun OR, PO, RV, QA, DS spawné (EX-018, TF-017). Sauter ce step en mode subagent-light et laisser PM-light piloter.
PM pré-spawne en UN SEUL BATCH la team fixe avant de transférer le pilotage à OR (modes team et subagent uniquement). OR ne pilote plus le spawn (cf. EX-004 — tool
Agentretiré du frontmatter d'OR). Aucunspawn_requestn'est émis par OR pour ces rôles fixes durant la totalité du workflow (TF-005).
Team fixe (toujours, team/subagent) : or, po, tl, rv, qa.
DS conditionnel : ajouté au batch ssi PRD.md frontmatter porte has_ui: true (TF-004).
DV : non spawné ici. Émission lazy après PLANNING:CHECKPOINT_TASKS (cf. Step 9).
# Mode subagent-light — SKIP this step entirely. PM-light handles TL spawn in Phase D.
# Mode team
TeamCreate already done at Step 4 → spawn each role as teammate
in a single PM turn (5 ou 6 spawns), with model=$WF_MODEL_<role>.
# Mode subagent
Single PM turn with N parallel Agent() calls:
Agent(subagent_type: wf-or, prompt: <bootstrap_need>)
Agent(subagent_type: wf-po, prompt: <stand-by — wait for OR brief>)
Agent(subagent_type: wf-tl, prompt: <stand-by>)
Agent(subagent_type: wf-rv, prompt: <stand-by>)
Agent(subagent_type: wf-qa, prompt: <stand-by>)
# if PRD.has_ui == true:
Agent(subagent_type: wf-ds, prompt: <stand-by>)
Critère opposable (TF-003 / TF-004) : à la sortie de BOOTSTRAP:SPAWN_TEAM,
wf/needs/<name>/.team-registry.json contient or, po, tl, rv, qa (et ds si
has_ui:true), pas dv.
Step 5.ter — Conditional watchdog (belt-and-suspenders)
System-critical (team mode only): the cron wakes PM up to detect STUCK teammates. Skipped in subagent mode — subagents are not idle between messages (they resume on each SendMessage), so there is no "idle-muet teammate" to repoke; PM stays in charge of every spawn and already knows the workflow state.
if [[ "$WF_AGENT_MODE" == "subagent" ]]; then
# No watchdog in subagent mode (no idle teammates to wake up).
# HO message: "Watchdog skipped (agent_mode=subagent)"
:
elif [[ "$WF_WATCHDOG_INTERVAL" != "off" ]]; then
DELAY_MIN="${WF_WATCHDOG_INTERVAL//min/}" # "3min" → "3"
# 1. PM invokes CronCreate (harness tool)
CronCreate(cron: "*/${DELAY_MIN} * * * *", prompt: "watchdog tick wf-<name>", recurring: true)
# 2. Touch the marker with the returned job_id — OR uses it to verify (safety net)
echo "<cron_job_id>" > wf/needs/<name>/.watchdog-cron-active
# HO message: "Watchdog active (${WF_WATCHDOG_INTERVAL})"
fi
If PM forgets this step (team mode only): OR detects the absence of .watchdog-cron-active and creates the cron itself (see agents/wf-or.md §Watchdog — belt-and-suspenders).
Step 5.bis — Register OR in the registry (traceability, optional)
For spawn traceability:
bash ${CLAUDE_PLUGIN_ROOT}/scripts/wf-registry.sh add <name> <or_agent_id> or
DEC-001: traceability only — enforcement uses
agent_typefrom the payload. Skipping this step does not prevent OR from completing its steps.
Step 6 — Bootstrap brief (PM → OR, format intent + context_files) — EX-001 / F1
Discipline brief opposable (INV-005) :
intent:+context_files:, corps horscontext_files:< 20 lignes, pas de paraphrase de PRD.md. Gabarit aligné suragents/wf-pm.md §Gabarits de briefs(T-003).
PM envoie à OR (à la sortie du batch Step 5) un seul bootstrap_need :
type: bootstrap_need
need: <name>
intent: <1 phrase ≤ 200 caractères — la mission HO synthétisée>
context_files:
- wf/needs/<name>/PRD.md
config:
agent_mode: <subagent|team>
dark_factory: <on|off>
language: <fr|en>
watchdog_interval: <WF_WATCHDOG_INTERVAL>
models: { or, po, tl, rv, qa, dv, ds }
review_loops: { artifacts, code }
# corps libre ≤ 20 lignes — pas de paraphrase de PRD.md
Critère opposable (TF-001) : champ intent: ≤ 200 caractères, champ
context_files: non vide, corps hors context_files: < 20 lignes, aucune
duplication du contenu de PRD.md.
OR enchaîne directement sur --query (l'init a été fait au Step 4.ter par PM —
pas de double-init côté OR).
Step 9 — Étape post-PLANNING : DV-lazy batch (EX-007)
Déclencheur : juste après
PLANNING:CHECKPOINT_TASKSvalidé. Cette étape est portée par PM (cf.agents/wf-pm.md §Responsabilité — DV-lazy batchpour l'algo détaillé).
Résumé de l'étape :
- PM lit
wf/needs/<name>/tasks.md→ liste tâches DV + dépendances. - PM calcule
N = max(parallélisme du chemin critique); plafond.wf-config.json:planning.max_dvsi défini. - PM log obligatoire (UNE seule ligne, format normatif) :
bash ${CLAUDE_PLUGIN_ROOT}/scripts/wf-orchestrate.sh <name> --log \ --msg "[DV-LAZY] N=<N> justification=<critical_path_width=K|max_dv=K> tasks=<count>" - PM émet UN SEUL batch de N spawns DV (pas N spawn_request unitaires).
- Cas N=0 (need pure-doc) : pas de spawn, state machine avance, exit 0 (TF-017).
Critère opposable (TF-015 / TF-016) :
- 0 spawn DV avant
PLANNING:CHECKPOINT_TASKS. - Une et une seule ligne
[DV-LAZY] N=<N>dansor.logaprès le checkpoint.
Step 9.bis — Dashboard TaskCreate (EX-001 dv-tasks-dashboard, modes team + subagent)
Déclencheur : juste après le DV-lazy batch (Step 9), avant que les DVs commencent à implémenter. Cette étape est portée par PM (cf.
agents/wf-pm.md §Dashboard TaskCreate batchpour l'algorithme détaillé). Non applicable en modesubagent-light(EX-006 dv-tasks-dashboard).
Résumé de l'étape :
- PM relit
wf/needs/<name>/tasks.md→ liste les lignesT-xxx. - PM appelle
TaskCreatepour chaqueT-xxxavec :subject= titre T-xxx,description= cellule Description de la ligne,metadata.t_id="T-xxx"(lookup ultérieur).
- PM stocke en mémoire la table
{t_id → taskId}retournée par CC. - PM log obligatoire :
bash ${CLAUDE_PLUGIN_ROOT}/scripts/wf-orchestrate.sh <name> --log \ --msg "[DASHBOARD] TaskCreate batch tasks=<N>"
Les status sont ensuite mis à jour par PM via TaskUpdate au fil des
t_status_update reçus (relay mode team) ou des marqueurs [T_STATUS]
trouvés dans l'output des Agent calls (mode subagent). Mapping
INV-007 → CC status défini dans agents/wf-pm.md §Dashboard TaskCreate batch.
Critère opposable : après cette étape, la TaskList de la conversation PM
contient exactement N tasks pending, chacune avec metadata.t_id unique
tracé à tasks.md.
Why PM resolves the name before OR (Flow Z)
- PM has the fresh verbal HO context — proposing kebab-case is trivial
- Avoids an OR↔PM↔HO round-trip for each name clarification
- OR starts with a complete brief and can immediately create
wf/needs/<name>/ - Name resolution is an HO interaction, not orchestration — it's PM's job
Rules
- Mandatory preflight — TeamCreate will fail if the flag is absent
- Name MUST be kebab-case — validate strictly
- No collision — check
wf/needs/<name>/before spawn - PM stays lean at bootstrap — name resolution + TeamCreate + OR spawn, then full delegation to OR
- One question at a time to HO during name resolution
- Session marker: OR creates
$HOME/.claude/wf-session-active.<session_id>after--init(session-scoped marker, required by/waterfall:resume). Thesession_idis$WF_SIDresolved in step 1.bis, passed via--session. NoleadSessionIdor"default"fallback (EX-010, INV-002). - Params
--team+--session:wf-orchestrate.sh <name> --init --team wf-<name> --session "$WF_SID"—WF_SIDis the only source of truth for the HO sid (EX-006, ADR-001).
IMPORTANT — SendMessage plain text obligatoire : le paramètre
messagedeSendMessagen'accepte questring. Utiliser le format plain textclé: valeur— jamais d'objet{...}, jamaisJSON.stringify().