nubos-pilot 1.3.3 → 1.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/np-task-architect.md +95 -0
- package/agents/np-test-writer.md +89 -0
- package/bin/install.js +73 -16
- package/bin/np-tools/commit-task.cjs +80 -6
- package/bin/np-tools/commit-task.test.cjs +133 -0
- package/bin/np-tools/loop-commands.test.cjs +121 -2
- package/bin/np-tools/loop-run-round.cjs +121 -5
- package/lib/agents-registry.cjs +10 -0
- package/lib/agents.test.cjs +2 -0
- package/lib/config-defaults.cjs +8 -0
- package/lib/config-schema.cjs +2 -0
- package/lib/git.cjs +6 -2
- package/lib/git.test.cjs +28 -0
- package/lib/template.cjs +20 -15
- package/lib/template.test.cjs +35 -0
- package/package.json +1 -1
- package/templates/RULES.md +36 -1
- package/workflows/execute-phase.md +138 -1
- package/workflows/plan-phase.md +17 -2
|
@@ -219,6 +219,10 @@ SPAWN_HEADLESS_ENABLED=$(node .nubos-pilot/bin/np-tools.cjs config-get spawn.hea
|
|
|
219
219
|
SPAWN_HEADLESS_AGENTS=$(node .nubos-pilot/bin/np-tools.cjs config-get spawn.headless.agents 2>/dev/null || echo '["np-critic","np-researcher"]')
|
|
220
220
|
SPAWN_HEADLESS_FALLBACK=$(node .nubos-pilot/bin/np-tools.cjs config-get spawn.headless.fallback_on_error 2>/dev/null || echo true)
|
|
221
221
|
CONF_INJECT_CRITERIA=$(node .nubos-pilot/bin/np-tools.cjs config-get conformance.inject_criteria 2>/dev/null || echo true)
|
|
222
|
+
# Round-1 prep agents (default on; backfilled on install/update). When a toggle
|
|
223
|
+
# is false the matching ACTION CONTRACT (Step 2b / Step 2c) is skipped wholesale.
|
|
224
|
+
ARCHITECT_ENABLED=$(node .nubos-pilot/bin/np-tools.cjs config-get agents.architect 2>/dev/null || echo true)
|
|
225
|
+
TEST_WRITER_ENABLED=$(node .nubos-pilot/bin/np-tools.cjs config-get agents.test_writer 2>/dev/null || echo true)
|
|
222
226
|
# Milestone success_criteria as the executor's acceptance target (rendered once from the INIT payload).
|
|
223
227
|
# Intent-level only (ADR-0019): these describe what "done right" means, NOT how to build it.
|
|
224
228
|
SUCCESS_CRITERIA_BLOCK=$(echo "$INIT" | node -e 'process.stdin.on("data",d=>{try{const c=JSON.parse(d).success_criteria||[];console.log(c.map(x=>"- "+(x.id?x.id+": ":"")+(x.text||x)).join("\n"))}catch(e){console.log("")}})')
|
|
@@ -414,6 +418,131 @@ for WAVE_INDEX in 0 1 2 ...; do
|
|
|
414
418
|
CONSENSUS_PATTERN=""
|
|
415
419
|
fi
|
|
416
420
|
|
|
421
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
422
|
+
# ACTION CONTRACT — Step 2b: Per-Task Architect (Round 1, config-gated)
|
|
423
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
424
|
+
# WHEN: $ROUND -eq 1 AND $ARCHITECT_ENABLED = true. Skip wholesale otherwise
|
|
425
|
+
# (agents.architect=false → no architect this run; R≥2 build-fixer rounds
|
|
426
|
+
# never run it).
|
|
427
|
+
# SKIP-GUARD: loop-post-architect-missing-spawn-audit (needs 1 architect audit).
|
|
428
|
+
#
|
|
429
|
+
# Execute EXACTLY these three groups, in order:
|
|
430
|
+
#
|
|
431
|
+
# (1) ONE Agent tool-call (real, not bash):
|
|
432
|
+
# Agent(subagent_type="np-task-architect", prompt=<…>)
|
|
433
|
+
# Prompt fields:
|
|
434
|
+
# <files_to_read>: task plan, slice plan, CONTEXT.md, RULES.md,
|
|
435
|
+
# M<NNN>-ARCHITECTURE.md (if present), .nubos-pilot/codebase/INDEX.md
|
|
436
|
+
# <consensus_pattern>: $CONSENSUS_PATTERN (researcher output; may be empty)
|
|
437
|
+
# <lang_directive>: $LANG_DIRECTIVE
|
|
438
|
+
# Curated skills (quality bar) — instruct the agent to Read each that
|
|
439
|
+
# applies from .claude/skills/<skill>/SKILL.md: np-system-design,
|
|
440
|
+
# np-service-boundary, np-api-design, np-composition-patterns,
|
|
441
|
+
# np-error-handling, np-adr (only for a costly-to-reverse choice).
|
|
442
|
+
# The agent is READ-ONLY: it emits its Task-Architecture spec as its FINAL
|
|
443
|
+
# MESSAGE (markdown per its Output Contract). Write that message verbatim
|
|
444
|
+
# to "$ARCH_CONSTRAINTS_PATH".
|
|
445
|
+
#
|
|
446
|
+
# (2) ONE Bash audit-stamp (same round) — architect is NOT Rule-9 audited,
|
|
447
|
+
# so an empty tool-use log is correct:
|
|
448
|
+
# node .nubos-pilot/bin/np-tools.cjs loop-audit-tool-use "$TASK_ID" \
|
|
449
|
+
# --agent np-task-architect --tool-use-log '[]'
|
|
450
|
+
#
|
|
451
|
+
# (3) ONE Bash advance:
|
|
452
|
+
# node .nubos-pilot/bin/np-tools.cjs loop-run-round "$TASK_ID" \
|
|
453
|
+
# --phase post-architect
|
|
454
|
+
#
|
|
455
|
+
# $ARCH_CONSTRAINTS is injected as <architecture_constraints> into the
|
|
456
|
+
# test-writer (Step 2c) AND executor (Step 3) prompts.
|
|
457
|
+
#
|
|
458
|
+
# Rationale: ADR-0023 — a per-task structural pass before tests/code so the
|
|
459
|
+
# test-writer and executor build against a decided shape, honouring RULES.md
|
|
460
|
+
# Conventions. Ephemeral ($TMPDIR, never committed) → plan-lint untouched.
|
|
461
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
462
|
+
ARCH_CONSTRAINTS=""
|
|
463
|
+
ARCH_CONSTRAINTS_PATH="${TMPDIR:-/tmp}/np-arch-${TASK_ID}.md"
|
|
464
|
+
if [ "$ROUND" -eq 1 ] && [ "$ARCHITECT_ENABLED" = "true" ]; then
|
|
465
|
+
# Off-host (ADR-0021): np-task-architect is read-only (Read/Grep/Glob), not
|
|
466
|
+
# Rule-9 audited, writes no files — run via spawn-offhost with default cwd
|
|
467
|
+
# when it routes to an openai-compat provider; its spec returns as the
|
|
468
|
+
# spawn's final message (content).
|
|
469
|
+
ARCHITECT_KIND=$(node .nubos-pilot/bin/np-tools.cjs resolve-model np-task-architect --json 2>/dev/null \
|
|
470
|
+
| node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{try{console.log(JSON.parse(s).kind||"native")}catch{console.log("native")}})')
|
|
471
|
+
if [ "$ARCHITECT_KIND" = "openai-compat" ]; then
|
|
472
|
+
A_PROMPT="${TMPDIR:-/tmp}/np-offhost-task-architect-${TASK_ID}.md"
|
|
473
|
+
# … render the files_to_read block + consensus + skills + $LANG_DIRECTIVE into "$A_PROMPT" …
|
|
474
|
+
A_OUT=$(node .nubos-pilot/bin/np-tools.cjs spawn-offhost \
|
|
475
|
+
--agent np-task-architect --task-file "$A_PROMPT" --task-id "$TASK_ID" \
|
|
476
|
+
--read-only --no-audit ${SLICE_CWD:+--cwd "$SLICE_CWD"})
|
|
477
|
+
echo "$A_OUT" | ARCH_PATH="$ARCH_CONSTRAINTS_PATH" node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{let c="";try{c=JSON.parse(s).content||""}catch{}require("fs").writeFileSync(process.env.ARCH_PATH,c)})'
|
|
478
|
+
else
|
|
479
|
+
true # → execute group (1): native Agent spawn; write its final message to "$ARCH_CONSTRAINTS_PATH".
|
|
480
|
+
fi
|
|
481
|
+
node .nubos-pilot/bin/np-tools.cjs loop-audit-tool-use "$TASK_ID" --agent np-task-architect --tool-use-log '[]'
|
|
482
|
+
node .nubos-pilot/bin/np-tools.cjs loop-run-round "$TASK_ID" --phase post-architect
|
|
483
|
+
[ -f "$ARCH_CONSTRAINTS_PATH" ] && ARCH_CONSTRAINTS=$(cat "$ARCH_CONSTRAINTS_PATH")
|
|
484
|
+
fi
|
|
485
|
+
|
|
486
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
487
|
+
# ACTION CONTRACT — Step 2c: Test-Writer / TDD (Round 1, config-gated)
|
|
488
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
489
|
+
# WHEN: $ROUND -eq 1 AND $TEST_WRITER_ENABLED = true. Runs AFTER the architect,
|
|
490
|
+
# BEFORE the executor. Skip wholesale otherwise.
|
|
491
|
+
# SKIP-GUARD: loop-post-test-writer-missing-spawn-audit (needs 1 test-writer audit).
|
|
492
|
+
#
|
|
493
|
+
# Execute EXACTLY these three groups, in order:
|
|
494
|
+
#
|
|
495
|
+
# (1) ONE Agent tool-call (real, not bash):
|
|
496
|
+
# Agent(subagent_type="np-test-writer", prompt=<…>)
|
|
497
|
+
# Prompt fields:
|
|
498
|
+
# <files_to_read>: task plan, slice plan, RULES.md, neighbouring tests
|
|
499
|
+
# <architecture_constraints>: $ARCH_CONSTRAINTS (the architect's required
|
|
500
|
+
# test surfaces; empty when the architect is disabled)
|
|
501
|
+
# <success_criteria>: $SUCCESS_CRITERIA_BLOCK + slice UAT path (intent-level)
|
|
502
|
+
# <lang_directive>: $LANG_DIRECTIVE
|
|
503
|
+
# Curated skill (quality bar) — instruct the agent to Read
|
|
504
|
+
# .claude/skills/np-test-strategy/SKILL.md and satisfy its Verification bar.
|
|
505
|
+
# RULES — the agent writes REAL, VALID test files for every required surface;
|
|
506
|
+
# it MUST NOT skip/stub/weaken assertions (Rule 10). Tests MAY be red now;
|
|
507
|
+
# the executor makes them green. The agent emits a JSON envelope whose
|
|
508
|
+
# tests_written paths you collect into $TDD_TESTS.
|
|
509
|
+
#
|
|
510
|
+
# (2) ONE Bash audit-stamp (same round) — test-writer is NOT Rule-9 audited:
|
|
511
|
+
# node .nubos-pilot/bin/np-tools.cjs loop-audit-tool-use "$TASK_ID" \
|
|
512
|
+
# --agent np-test-writer --tool-use-log '[]'
|
|
513
|
+
#
|
|
514
|
+
# (3) ONE Bash advance — pass the written test paths so they are recorded in
|
|
515
|
+
# the checkpoint (nubosloop.tdd_tests) and commit-task folds them into the
|
|
516
|
+
# commit even when files_modified did not enumerate them:
|
|
517
|
+
# node .nubos-pilot/bin/np-tools.cjs loop-run-round "$TASK_ID" \
|
|
518
|
+
# --phase post-test-writer --tests "$TDD_TESTS"
|
|
519
|
+
#
|
|
520
|
+
# Rationale: ADR-0023 — TDD inside the loop. The mechanical verify gate
|
|
521
|
+
# (Step 4) runs only AFTER the executor, so red-until-executor is expected
|
|
522
|
+
# and not a failure. The np-critic-tests axis (Step 5) re-audits for any
|
|
523
|
+
# skipped/vacuous assertions that slipped through.
|
|
524
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
525
|
+
TDD_TESTS=""
|
|
526
|
+
if [ "$ROUND" -eq 1 ] && [ "$TEST_WRITER_ENABLED" = "true" ]; then
|
|
527
|
+
# Off-host (ADR-0021): np-test-writer writes test files, so off-host needs
|
|
528
|
+
# worktree isolation exactly like the executor (model-driven Write confined
|
|
529
|
+
# + ff-merged back). When worktree isolation is off, it runs native.
|
|
530
|
+
TEST_WRITER_KIND=$(node .nubos-pilot/bin/np-tools.cjs resolve-model np-test-writer --json 2>/dev/null \
|
|
531
|
+
| node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{try{console.log(JSON.parse(s).kind||"native")}catch{console.log("native")}})')
|
|
532
|
+
if [ "$TEST_WRITER_KIND" = "openai-compat" ] && [ "$WORKTREE_ISOLATION" = "true" ] && [ -n "$SLICE_CWD" ] && [ "$SLICE_CWD" != "." ]; then
|
|
533
|
+
TW_PROMPT="${TMPDIR:-/tmp}/np-offhost-test-writer-${TASK_ID}.md"
|
|
534
|
+
# … render files_to_read + architecture_constraints + success_criteria + skill + $LANG_DIRECTIVE into "$TW_PROMPT" …
|
|
535
|
+
TW_OUT=$(node .nubos-pilot/bin/np-tools.cjs spawn-offhost \
|
|
536
|
+
--agent np-test-writer --task-file "$TW_PROMPT" --task-id "$TASK_ID" \
|
|
537
|
+
--cwd "$SLICE_CWD" --allow-bash --no-audit)
|
|
538
|
+
TDD_TESTS=$(echo "$TW_OUT" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{try{const j=JSON.parse(JSON.parse(s).content||"{}");console.log((j.tests_written||[]).join(", "))}catch{console.log("")}})')
|
|
539
|
+
else
|
|
540
|
+
true # → execute group (1): native Agent spawn; collect tests_written from the envelope into $TDD_TESTS.
|
|
541
|
+
fi
|
|
542
|
+
node .nubos-pilot/bin/np-tools.cjs loop-audit-tool-use "$TASK_ID" --agent np-test-writer --tool-use-log '[]'
|
|
543
|
+
node .nubos-pilot/bin/np-tools.cjs loop-run-round "$TASK_ID" --phase post-test-writer --tests "$TDD_TESTS"
|
|
544
|
+
fi
|
|
545
|
+
|
|
417
546
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
418
547
|
# ACTION CONTRACT — Step 3: Executor (R1) / Build-Fixer (R≥2)
|
|
419
548
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
@@ -424,6 +553,13 @@ for WAVE_INDEX in 0 1 2 ...; do
|
|
|
424
553
|
# Prompt fields:
|
|
425
554
|
# <files_to_read>: task plan, slice plan, prior slice SUMMARYs, CONTEXT.md
|
|
426
555
|
# <consensus_pattern>: $CONSENSUS_PATTERN (with [VERIFIED]/[PROVISIONAL]/[CACHED])
|
|
556
|
+
# <architecture_constraints>: $ARCH_CONSTRAINTS — the per-task architect's
|
|
557
|
+
# decided structure + constraints (empty when agents.architect is off).
|
|
558
|
+
# The executor builds against this shape; it is intent-level, not a code spec.
|
|
559
|
+
# <tdd_tests>: $TDD_TESTS — test files np-test-writer wrote (R1, empty when off).
|
|
560
|
+
# The executor MUST make them green WITHOUT deleting, skipping, or weakening
|
|
561
|
+
# any assertion. They are in scope alongside files_modified (recorded in the
|
|
562
|
+
# checkpoint at post-test-writer) and commit-task commits them with the diff.
|
|
427
563
|
# <success_criteria>: when $CONF_INJECT_CRITERIA = true, include the milestone
|
|
428
564
|
# acceptance target — $SUCCESS_CRITERIA_BLOCK plus the slice UAT path
|
|
429
565
|
# (.nubos-pilot/milestones/M<NNN>/slices/S<NNN>/S<NNN>-UAT.md). Frame it as
|
|
@@ -437,7 +573,8 @@ for WAVE_INDEX in 0 1 2 ...; do
|
|
|
437
573
|
# ultra) instruct the agent to APPLY the np-executor "Climb the ladder"
|
|
438
574
|
# discipline before writing (prevention-first). When $ECONOMY_MODE = off,
|
|
439
575
|
# instruct it to SKIP the ladder (no economy pressure this run).
|
|
440
|
-
# RULES — Agent MUST: edit ONLY paths in files_modified
|
|
576
|
+
# RULES — Agent MUST: edit ONLY paths in files_modified plus the <tdd_tests>
|
|
577
|
+
# paths (D-04 scope guard; the TDD tests are the sole sanctioned addition) —
|
|
441
578
|
# success_criteria are the acceptance target, NEVER a licence to touch other files,
|
|
442
579
|
# run `node np-tools.cjs knowledge-search "<q>" --task $TASK_ID` via Bash
|
|
443
580
|
# ≥1× (Rule 9 — the --task flag writes the audit evidence ledger),
|
package/workflows/plan-phase.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
command: np:plan-phase
|
|
3
3
|
description: Plans a milestone (M<NNN>) — breaks it into slices (waves) and tasks. Spawns np-planner (opus) + np-plan-checker (opus), 2-iteration verification, then scaffolds every task file.
|
|
4
|
-
argument-hint: <milestone-number> [--research] [--repromote]
|
|
4
|
+
argument-hint: <milestone-number> [--research] [--architect] [--repromote]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# np:plan-phase
|
|
@@ -41,17 +41,19 @@ Output layout:
|
|
|
41
41
|
```bash
|
|
42
42
|
PHASE=""
|
|
43
43
|
RESEARCH_FLAG=0
|
|
44
|
+
ARCHITECT_FLAG=0
|
|
44
45
|
REPROMOTE_FLAG=0
|
|
45
46
|
for arg in "$@"; do
|
|
46
47
|
case "$arg" in
|
|
47
48
|
--research) RESEARCH_FLAG=1 ;;
|
|
49
|
+
--architect) ARCHITECT_FLAG=1 ;;
|
|
48
50
|
--repromote) REPROMOTE_FLAG=1 ;;
|
|
49
51
|
--*) echo "Unknown flag: $arg" >&2; exit 2 ;;
|
|
50
52
|
*) [[ -z "$PHASE" ]] && PHASE="$arg" ;;
|
|
51
53
|
esac
|
|
52
54
|
done
|
|
53
55
|
if [[ -z "$PHASE" ]]; then
|
|
54
|
-
echo "Usage: /np:plan-phase <milestone-number> [--research] [--repromote]" >&2
|
|
56
|
+
echo "Usage: /np:plan-phase <milestone-number> [--research] [--architect] [--repromote]" >&2
|
|
55
57
|
exit 2
|
|
56
58
|
fi
|
|
57
59
|
```
|
|
@@ -154,6 +156,19 @@ fi
|
|
|
154
156
|
|
|
155
157
|
**Exit code 42 contract:** orchestrator sees exit 42 → runs `/np:research-phase $PHASE` → re-enters `/np:plan-phase $PHASE` without the `--research` flag.
|
|
156
158
|
|
|
159
|
+
### Gate 2b — Optional architecture pass (`--architect`)
|
|
160
|
+
|
|
161
|
+
The `--architect` flag auto-dispatches `/np:architect-phase` before planning, so a structural ADR pass (`M<NNN>-ARCHITECTURE.md`) is decided up front and the planner consumes it like an extension of CONTEXT.md. Dispatched AFTER research (the established flow is research → architect → plan): when both flags are set, the research re-entry strips `--research`, leaving `--architect` to dispatch on the next pass.
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
if [[ "$ARCHITECT_FLAG" == "1" ]]; then
|
|
165
|
+
echo "architect-auto: dispatching /np:architect-phase $PHASE before planning" >&2
|
|
166
|
+
exit 43
|
|
167
|
+
fi
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Exit code 43 contract:** orchestrator sees exit 43 → runs `/np:architect-phase $PHASE` → re-enters `/np:plan-phase $PHASE` without the `--architect` flag. The milestone `np-architect` stays intent-level (ADR-0019): its decisions inform the plan; they do not bake schema/filenames/code-style into `PLAN.md`.
|
|
171
|
+
|
|
157
172
|
**Researcher-Schwarm semantics (ADR-0011).** The dispatched `/np:research-phase` runs in Schwarm mode by default (`swarm.research.k=3`). The cache-bypass at Pre-flight short-circuits the swarm whenever the milestone goal + requirements match a stored learning at similarity ≥ `swarm.research.threshold` and `occurrence ≥ swarm.research.minOccurrence`. The merged consensus carries a `<consensus_meta>` block (`k`, `agreement_score`, `flagged_decisions`) which `np-plan-checker` reads to weight downstream verdicts. No additional flags needed at this site — the swarm runs automatically when `--research` is set.
|
|
158
173
|
|
|
159
174
|
### Gate 3 — Milestone already planned
|