Skip to content

Execution Workflows

Wave-based execution, atomic commits, task lifecycle CRUD. Every commit produced here obeys ADR-0004: one task, one commit, subject prefix task(M<NNN>-S<NNN>-T<NNNN>):.

np:execute-phase <N> [--verify-work]

The execution entry point. Reads milestone N's slices (waves) and their tasks, dispatches each slice in order. Every task runs through the Nubosloop; a single-pass executor → commit-task is forbidden (ADR-0010).

--verify-work is an opt-in chain. When passed, the workflow runs /np:verify-work $PHASE automatically after every slice is committed and finalize-milestone has produced the slice summaries. It carries the same hard-fail contract as a manual /np:verify-work (exit 1 on any Fail SC). Without the flag the workflow stops after finalize-milestone and verify-work stays a separate manual step, which is the right default when the operator wants to inspect commits before running the verifier. The flag appears in the init payload as auto_verify: true.

For each slice in order:

  1. Dispatch every task of the slice in parallel. Each task is one independent Nubosloop instance.
  2. Wait until every task in the slice is committed OR is stuck OR hit plan-checker.
  3. If any task is stuck or hit plan-checker, stop the wave and exit non-zero. Previously committed tasks remain committed.
  4. Move to the next slice.

When workflow.worktree_isolation: true, each slice runs inside an isolated git worktree (created at slice-start, fast-forward-merged + removed at slice-end). On failure the worktree stays in place for inspection — clean up with /np:reset-slice. See ADR-0008 for the full mechanism.

Per-task Nubosloop (6 steps)

Per task, per round (default cap loop.maxRounds=3):

  1. Pre-flight cache lookup (Round 1) — loop-run-round --phase preflight checks learnings.json for a cached pattern; a hit short-circuits the Researcher-Schwarm.
  2. Researcher-Schwarm (on cache miss or re-route) — swarm.research.k=3 parallel np-researcher spawns. Each writes a schema-bound research/spawn-<i>.md (researcher-output schema, hard-gated post-write). The deterministic mergeConsensus proposes; np-researcher-reconciler (Stage 2, ADR-0018) reads all spawns plus the proposal, classifies reasoning-trace agreement, picks contested decisions, and writes the final M<NNN>-RESEARCH.md. A disagreement hard-gate keyed on agreement_score and contested_count raises an askuser prompt when the swarm has not converged. Layer-C requires k audit entries (k-of-k gate).
  3. Executor (R1) or Build-Fixer (R≥2) — a single LLM spawn writes code in files_modified. Build-Fixer takes prior critic findings plus verify output as input.
  4. Mechanical Checks — the orchestrator runs the task's verify command plus stack linters (phpstan, pint, tsc, eslint); loop-audit-tool-use audits Rule 9 (search-tool invocation) per spawn.
  5. Critic (verify-green) — one np-critic (sonnet) spawns and audits all three axes (style, tests, acceptance) in a single structured JSON. Per the Verdict-Only Contract (ADR-0010 §L5), the critic writes the full findings JSON to <report_path> and emits a small envelope as its final message, which keeps parent-context tokens bounded.
  6. Routeloop-run-round --phase post-critics --critic-outputs-path <file> returns next_action ∈ {commit, executor, researcher, askuser, plan-checker, stuck}. Zero findings routes to commit-task. Otherwise it spawns the routed destination, increments the round, and returns to Step 3.

Headless-Subprocess Mode (Cost Layer L6, opt-in) routes the critic and researcher spawns through a claude -p subprocess for true parent-context detach when the runtime's native Agent tool is too costly. Default spawn.headless.enabled=false. See ADR-0010 §L6 and Configuration → spawn.

Stuck escalation

Hitting loop.maxRounds triggers a four-option askuser dialog: continue +5 rounds, replan, mark stuck, manual fix. A next_action=plan-checker route (locked-decision-violation, infrastructure-mismatch) gets a three-option dialog: replan, stuck, manual-fix. The loop always pulls the operator into the decision rather than exiting silently.

bash
/np:execute-phase 1
# or, auto-chain into verify-work on success:
/np:execute-phase 1 --verify-work

np:verify-work <N>

Post-execution verification. Spawns np-verifier (tier=sonnet) which reads the milestone's ROADMAP + CONTEXT, every slice's PLAN + SUMMARY, every task's PLAN + SUMMARY, and the task commits.

Output: M<NNN>-VERIFICATION.md with one entry per success_criterion. Each entry carries a status of Pass, Fail, Defer, or Pending. Subjective criteria (UX, "feels", usability) are left at Pending with a needs_user_confirm flag set; the pass-2 askuser gate resolves those interactively. Any Fail makes the workflow exit non-zero.

bash
/np:verify-work 1

np:validate-phase <N>

Nyquist coverage audit. Spawns np-nyquist-auditor (tier=haiku) which walks every requirement in milestone scope and scores it COVERED / UNDER_SAMPLED / UNCOVERED based on whether at least one test observes the requirement's behavior directly. Writes M<NNN>-VALIDATION.md.

np:add-tests <N>

Persists Pass-classified cases from M<NNN>-VERIFICATION.md into test/uat/m<nnn>-<slug>.test.cjs using node:test format. Sentinel-preserving: user-authored tests outside the // >>> np:add-tests begin / end markers survive regeneration.

np:commit-task <M-S-T>

Atomic per-task git commit. Routes through lib/git.cjs:

  1. assertCommittablePaths(files_modified) — hard-fails when all declared paths are gitignored; warns on partial.
  2. git add -- <files_modified> (no -A, no .).
  3. git commit -m "task(<M-S-T>): <title>".
  4. Deletes the task's checkpoint at .nubos-pilot/checkpoints/<M-S-T>.json on success.
  5. Flips the task frontmatter status to done.

The executor calls it; the user does not invoke it directly. If you ever need to manually finalize a task, this is the only safe way.

Since commit-task routes through lib/tasks.cjs::setTaskStatus, it also re-renders the slice's TODO.md rollup. The same is true for /np:skip, /np:park, /np:unpark, and /np:undo-task — every task-status transition keeps the slice TODO view live.

np:checkpoint

Per-task crash-safety pointer CRUD. Subcommands:

  • start <M-S-T> — write initial checkpoint with pending status.
  • transition <M-S-T> <new-status>pendingin-progressverifyingpre-commit.
  • touch <M-S-T> — heartbeat update.
  • show <M-S-T> — print the checkpoint JSON.

The executor uses transition exclusively. Direct Read/Write on the JSON is forbidden, because the wrapper enforces invariants.

np:pause-work

Stamps STATE.session.stopped_at and writes STATE.resume_file for an explicit handoff. Use this when stepping away mid-task; /np:resume-work will pick up cleanly later.

pause-work also captures a session snapshot to .nubos-pilot/state/session-snapshot.json (gitignored): current milestone and task, the last 10 task commits, every still-open / read handoff, and the live checkpoint ids. The snapshot is a best-effort write. Failures don't block the pause; the JSON payload returns snapshot_path and snapshot_error so the workflow can surface either.

np:resume-work

Classifies the current session state as one of:

  • resume — explicit pause, resume_file present, continue from there.
  • orphan — checkpoints exist but no pause was logged; the agent likely crashed.
  • clean — no checkpoints, nothing in flight; start fresh.

Use after re-opening the host CLI on a project that was mid-execution.

Session-snapshot block. When .nubos-pilot/state/session-snapshot.json exists from a prior /np:pause-work, the JSON payload also includes a session_snapshot block with the captured milestone, task, last-5-commits, and open handoffs. The orchestrator surfaces this so operators (and re-spawned executors) re-enter with continuity context and do not have to re-read every milestone artifact to remember where they were.

Worktree awareness. When workflow.worktree_isolation is enabled, the JSON payload also includes:

  • worktree_isolation: true (always, so callers can branch)
  • worktree: { slice_full_id, branch, path } (when the current task's slice has an active worktree; this is where the orchestrator should cd before re-spawning the executor)
  • stale_worktrees[] (any worktrees whose branch does NOT match the current task's slice: orphans from prior crashes, candidates for manual cleanup)

np:undo <N | M<NNN>-S<NNN>>

Revert every task commit of a milestone or slice via git revert --no-edit, with no history rewrite. Newest-first so dependency chains unwind cleanly. Every affected task's frontmatter is reset to pending so the next /np:execute-phase picks them up again.

bash
/np:undo 1                # revert every task of milestone M001
/np:undo M001-S002        # revert every task of slice M001-S002

np:undo-task <M-S-T>

Single-task variant. Reverts exactly one task's commit via git revert --no-edit, resets the task frontmatter status to pending.

bash
/np:undo-task M001-S001-T0003

np:reset-slice [<M-S-T>]

Crash-recovery. Discards the in-flight task (named in STATE.current_task or passed explicitly): restores files_modified from HEAD via git restore, deletes the checkpoint, clears STATE.current_task. It does not commit or revert. Use this when execution crashed before the commit landed; use /np:undo-task instead when the commit already exists.

When workflow.worktree_isolation is on, reset-slice also removes the slice's worktree and deletes the np/<mid>-<sid> branch (unless --keep-worktree is passed). See ADR-0008.

np:skip / np:park / np:unpark

Lightweight task lifecycle CRUD:

  • /np:skip <M-S-T> — mark status: skipped. Use for tasks made obsolete mid-milestone.
  • /np:park <M-S-T> — mark status: parked. Use for tasks blocked on something external.
  • /np:unpark <M-S-T> — return a parked task to pending.

All three update task frontmatter, route through setTaskStatus, and therefore also re-render the owning slice's TODO.md rollup. None of them produce a git commit on their own.