nubos-pilot 0.1.0

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.
Files changed (273) hide show
  1. package/agents/np-ai-researcher.md +140 -0
  2. package/agents/np-code-fixer.md +363 -0
  3. package/agents/np-code-reviewer.md +351 -0
  4. package/agents/np-domain-researcher.md +136 -0
  5. package/agents/np-eval-auditor.md +167 -0
  6. package/agents/np-eval-planner.md +153 -0
  7. package/agents/np-executor.md +72 -0
  8. package/agents/np-framework-selector.md +171 -0
  9. package/agents/np-nyquist-auditor.md +185 -0
  10. package/agents/np-plan-checker.md +165 -0
  11. package/agents/np-planner.md +199 -0
  12. package/agents/np-researcher.md +150 -0
  13. package/agents/np-security-auditor.md +206 -0
  14. package/agents/np-ui-auditor.md +369 -0
  15. package/agents/np-ui-checker.md +192 -0
  16. package/agents/np-ui-researcher.md +324 -0
  17. package/agents/np-verifier.md +79 -0
  18. package/bin/check-coverage.cjs +40 -0
  19. package/bin/check-workflows.cjs +171 -0
  20. package/bin/check-workflows.test.cjs +208 -0
  21. package/bin/install.js +500 -0
  22. package/bin/np-tools/_commands.cjs +70 -0
  23. package/bin/np-tools/add-tests.cjs +171 -0
  24. package/bin/np-tools/add-tests.test.cjs +122 -0
  25. package/bin/np-tools/add-todo.cjs +108 -0
  26. package/bin/np-tools/add-todo.test.cjs +112 -0
  27. package/bin/np-tools/agent-skills.cjs +14 -0
  28. package/bin/np-tools/agent-skills.test.cjs +42 -0
  29. package/bin/np-tools/ai-integration-phase.cjs +109 -0
  30. package/bin/np-tools/ai-integration-phase.test.cjs +123 -0
  31. package/bin/np-tools/askuser.cjs +53 -0
  32. package/bin/np-tools/askuser.test.cjs +49 -0
  33. package/bin/np-tools/autonomous.cjs +69 -0
  34. package/bin/np-tools/autonomous.test.cjs +74 -0
  35. package/bin/np-tools/checkpoint.cjs +101 -0
  36. package/bin/np-tools/checkpoint.test.cjs +119 -0
  37. package/bin/np-tools/code-review.cjs +133 -0
  38. package/bin/np-tools/code-review.test.cjs +96 -0
  39. package/bin/np-tools/commit-task.cjs +120 -0
  40. package/bin/np-tools/commit-task.test.cjs +160 -0
  41. package/bin/np-tools/commit.cjs +103 -0
  42. package/bin/np-tools/commit.test.cjs +93 -0
  43. package/bin/np-tools/config.cjs +101 -0
  44. package/bin/np-tools/config.test.cjs +71 -0
  45. package/bin/np-tools/discuss-phase-power.cjs +265 -0
  46. package/bin/np-tools/discuss-phase-power.test.cjs +242 -0
  47. package/bin/np-tools/discuss-phase.cjs +132 -0
  48. package/bin/np-tools/discuss-phase.test.cjs +148 -0
  49. package/bin/np-tools/dispatch.cjs +116 -0
  50. package/bin/np-tools/doctor.cjs +242 -0
  51. package/bin/np-tools/eval-review.cjs +116 -0
  52. package/bin/np-tools/eval-review.test.cjs +123 -0
  53. package/bin/np-tools/execute-phase.cjs +182 -0
  54. package/bin/np-tools/execute-phase.test.cjs +116 -0
  55. package/bin/np-tools/execute-plan.cjs +124 -0
  56. package/bin/np-tools/execute-plan.test.cjs +82 -0
  57. package/bin/np-tools/help.cjs +28 -0
  58. package/bin/np-tools/help.test.cjs +29 -0
  59. package/bin/np-tools/init-dispatch.test.cjs +91 -0
  60. package/bin/np-tools/metrics.cjs +97 -0
  61. package/bin/np-tools/metrics.test.cjs +188 -0
  62. package/bin/np-tools/new-milestone.cjs +288 -0
  63. package/bin/np-tools/new-milestone.test.cjs +166 -0
  64. package/bin/np-tools/new-project.cjs +284 -0
  65. package/bin/np-tools/new-project.test.cjs +165 -0
  66. package/bin/np-tools/next.cjs +7 -0
  67. package/bin/np-tools/next.test.cjs +30 -0
  68. package/bin/np-tools/park.cjs +48 -0
  69. package/bin/np-tools/park.test.cjs +50 -0
  70. package/bin/np-tools/pause-work.cjs +24 -0
  71. package/bin/np-tools/pause-work.test.cjs +74 -0
  72. package/bin/np-tools/phase.cjs +71 -0
  73. package/bin/np-tools/phase.test.cjs +81 -0
  74. package/bin/np-tools/plan-diff.cjs +57 -0
  75. package/bin/np-tools/plan-diff.test.cjs +134 -0
  76. package/bin/np-tools/plan-milestone-gaps.cjs +115 -0
  77. package/bin/np-tools/plan-milestone-gaps.test.cjs +122 -0
  78. package/bin/np-tools/plan-phase.cjs +350 -0
  79. package/bin/np-tools/plan-phase.test.cjs +263 -0
  80. package/bin/np-tools/progress.cjs +7 -0
  81. package/bin/np-tools/progress.test.cjs +44 -0
  82. package/bin/np-tools/queue.cjs +213 -0
  83. package/bin/np-tools/research-phase.cjs +144 -0
  84. package/bin/np-tools/research-phase.test.cjs +154 -0
  85. package/bin/np-tools/reset-slice.cjs +17 -0
  86. package/bin/np-tools/reset-slice.test.cjs +96 -0
  87. package/bin/np-tools/resolve-model.cjs +110 -0
  88. package/bin/np-tools/resolve-model.test.cjs +200 -0
  89. package/bin/np-tools/resume-work.cjs +76 -0
  90. package/bin/np-tools/resume-work.test.cjs +91 -0
  91. package/bin/np-tools/skip.cjs +48 -0
  92. package/bin/np-tools/skip.test.cjs +66 -0
  93. package/bin/np-tools/slug.cjs +34 -0
  94. package/bin/np-tools/slug.test.cjs +46 -0
  95. package/bin/np-tools/state.cjs +16 -0
  96. package/bin/np-tools/state.test.cjs +40 -0
  97. package/bin/np-tools/stats.cjs +151 -0
  98. package/bin/np-tools/stats.test.cjs +118 -0
  99. package/bin/np-tools/triage.cjs +128 -0
  100. package/bin/np-tools/ui-phase.cjs +108 -0
  101. package/bin/np-tools/ui-phase.test.cjs +121 -0
  102. package/bin/np-tools/ui-review.cjs +108 -0
  103. package/bin/np-tools/ui-review.test.cjs +120 -0
  104. package/bin/np-tools/undo-task.cjs +31 -0
  105. package/bin/np-tools/undo-task.test.cjs +117 -0
  106. package/bin/np-tools/undo.cjs +43 -0
  107. package/bin/np-tools/undo.test.cjs +120 -0
  108. package/bin/np-tools/unpark.cjs +48 -0
  109. package/bin/np-tools/unpark.test.cjs +50 -0
  110. package/bin/np-tools/verify-work.cjs +186 -0
  111. package/bin/np-tools/verify-work.test.cjs +97 -0
  112. package/docs/adr/0001-no-daemon-invariant.md +82 -0
  113. package/docs/adr/0002-zero-runtime-dependencies.md +90 -0
  114. package/docs/adr/0003-max-six-unit-types.md +85 -0
  115. package/docs/adr/0004-atomic-commit-per-unit.md +102 -0
  116. package/docs/adr/0005-three-orthogonal-file-trees.md +98 -0
  117. package/docs/adr/0006-yaml-dependency-amendment.md +60 -0
  118. package/docs/adr/README.md +27 -0
  119. package/docs/agent-frontmatter-schema.md +84 -0
  120. package/docs/phase-artifact-schemas.md +292 -0
  121. package/docs/phase-directory-layout.md +82 -0
  122. package/lib/__tests__/README.md +1 -0
  123. package/lib/agents.cjs +98 -0
  124. package/lib/agents.test.cjs +286 -0
  125. package/lib/askuser.cjs +36 -0
  126. package/lib/askuser.test.cjs +310 -0
  127. package/lib/checkpoint.cjs +135 -0
  128. package/lib/checkpoint.test.cjs +184 -0
  129. package/lib/core.cjs +165 -0
  130. package/lib/core.test.cjs +405 -0
  131. package/lib/fixtures/README.md +1 -0
  132. package/lib/fixtures/phase-tree/README.md +1 -0
  133. package/lib/fixtures/plans/cycle/PLAN.md +16 -0
  134. package/lib/fixtures/plans/cycle/tasks/T-01.md +20 -0
  135. package/lib/fixtures/plans/cycle/tasks/T-02.md +20 -0
  136. package/lib/fixtures/plans/cycle/tasks/T-03.md +20 -0
  137. package/lib/fixtures/plans/linear/PLAN.md +16 -0
  138. package/lib/fixtures/plans/linear/tasks/T-01.md +20 -0
  139. package/lib/fixtures/plans/linear/tasks/T-02.md +20 -0
  140. package/lib/fixtures/plans/linear/tasks/T-03.md +20 -0
  141. package/lib/fixtures/plans/parallel/PLAN.md +16 -0
  142. package/lib/fixtures/plans/parallel/tasks/T-01.md +20 -0
  143. package/lib/fixtures/plans/parallel/tasks/T-02.md +20 -0
  144. package/lib/fixtures/plans/parallel/tasks/T-03.md +20 -0
  145. package/lib/fixtures/plans/wave-conflict/PLAN.md +16 -0
  146. package/lib/fixtures/plans/wave-conflict/tasks/T-01.md +20 -0
  147. package/lib/fixtures/plans/wave-conflict/tasks/T-02.md +20 -0
  148. package/lib/fixtures/roadmap/ROADMAP-malformed.md +3 -0
  149. package/lib/fixtures/roadmap/ROADMAP-minimal.md +51 -0
  150. package/lib/fixtures/roadmap/roadmap-malformed.yaml +7 -0
  151. package/lib/fixtures/roadmap/roadmap-minimal.yaml +40 -0
  152. package/lib/fixtures/roadmap/roadmap-ten-phases.yaml +101 -0
  153. package/lib/fixtures/templates/phase-context.md +6 -0
  154. package/lib/fixtures/templates/plan-skeleton.md +6 -0
  155. package/lib/frontmatter.cjs +251 -0
  156. package/lib/frontmatter.test.cjs +177 -0
  157. package/lib/gaps.cjs +197 -0
  158. package/lib/gaps.test.cjs +200 -0
  159. package/lib/git.cjs +207 -0
  160. package/lib/git.test.cjs +305 -0
  161. package/lib/install/agents-md.cjs +77 -0
  162. package/lib/install/backup.cjs +70 -0
  163. package/lib/install/codex-toml.cjs +440 -0
  164. package/lib/install/managed-block.cjs +30 -0
  165. package/lib/install/manifest.cjs +148 -0
  166. package/lib/install/mcp-writer.cjs +127 -0
  167. package/lib/install/runtime-detect.cjs +44 -0
  168. package/lib/install/staging.cjs +149 -0
  169. package/lib/metrics-aggregate.cjs +229 -0
  170. package/lib/metrics-aggregate.test.cjs +192 -0
  171. package/lib/metrics.cjs +120 -0
  172. package/lib/metrics.test.cjs +182 -0
  173. package/lib/model-aliases.regression.test.cjs +16 -0
  174. package/lib/model-profiles.cjs +42 -0
  175. package/lib/model-profiles.test.cjs +61 -0
  176. package/lib/next.cjs +236 -0
  177. package/lib/next.test.cjs +194 -0
  178. package/lib/phase.cjs +95 -0
  179. package/lib/phase.test.cjs +189 -0
  180. package/lib/plan-checker-contract.test.cjs +72 -0
  181. package/lib/plan-diff.cjs +173 -0
  182. package/lib/plan-diff.test.cjs +217 -0
  183. package/lib/plan.cjs +85 -0
  184. package/lib/plan.test.cjs +263 -0
  185. package/lib/progress.cjs +95 -0
  186. package/lib/progress.test.cjs +116 -0
  187. package/lib/researcher-contract.test.cjs +61 -0
  188. package/lib/roadmap-render.cjs +206 -0
  189. package/lib/roadmap-render.test.cjs +121 -0
  190. package/lib/roadmap.cjs +416 -0
  191. package/lib/roadmap.test.cjs +371 -0
  192. package/lib/runtime/_contract.test.cjs +61 -0
  193. package/lib/runtime/_readline.cjs +119 -0
  194. package/lib/runtime/_readline.test.cjs +126 -0
  195. package/lib/runtime/claude.cjs +48 -0
  196. package/lib/runtime/claude.test.cjs +101 -0
  197. package/lib/runtime/codex.cjs +35 -0
  198. package/lib/runtime/codex.test.cjs +114 -0
  199. package/lib/runtime/gemini.cjs +35 -0
  200. package/lib/runtime/gemini.test.cjs +109 -0
  201. package/lib/runtime/index.cjs +49 -0
  202. package/lib/runtime/index.test.cjs +181 -0
  203. package/lib/runtime/opencode.cjs +35 -0
  204. package/lib/runtime/opencode.test.cjs +124 -0
  205. package/lib/state.cjs +205 -0
  206. package/lib/state.test.cjs +264 -0
  207. package/lib/surface-audit.test.cjs +46 -0
  208. package/lib/tasks.cjs +327 -0
  209. package/lib/tasks.test.cjs +389 -0
  210. package/lib/template.cjs +66 -0
  211. package/lib/template.test.cjs +159 -0
  212. package/lib/undo.cjs +179 -0
  213. package/lib/undo.test.cjs +261 -0
  214. package/lib/verify.cjs +116 -0
  215. package/lib/verify.test.cjs +187 -0
  216. package/np-tools.cjs +303 -0
  217. package/package.json +39 -0
  218. package/templates/AI-SPEC.md +90 -0
  219. package/templates/CONTEXT.md +32 -0
  220. package/templates/PLAN.md +69 -0
  221. package/templates/PROJECT.md +60 -0
  222. package/templates/REQUIREMENTS.md +38 -0
  223. package/templates/SECURITY.md +61 -0
  224. package/templates/UI-SPEC.md +64 -0
  225. package/templates/VALIDATION.md +76 -0
  226. package/templates/claude/payload/README.md +11 -0
  227. package/templates/opencode/opencode.json +6 -0
  228. package/templates/opencode/payload/AGENTS.md +9 -0
  229. package/workflows/add-backlog.md +212 -0
  230. package/workflows/add-tests.md +69 -0
  231. package/workflows/add-todo.md +222 -0
  232. package/workflows/ai-integration-phase.md +230 -0
  233. package/workflows/autonomous.md +94 -0
  234. package/workflows/cleanup.md +325 -0
  235. package/workflows/code-review-fix.md +435 -0
  236. package/workflows/code-review.md +447 -0
  237. package/workflows/discuss-phase-assumptions.md +269 -0
  238. package/workflows/discuss-phase-power.md +139 -0
  239. package/workflows/discuss-phase.md +386 -0
  240. package/workflows/dispatch.md +9 -0
  241. package/workflows/doctor.md +10 -0
  242. package/workflows/eval-review.md +243 -0
  243. package/workflows/execute-phase.md +142 -0
  244. package/workflows/execute-plan.md +82 -0
  245. package/workflows/help.md +8 -0
  246. package/workflows/new-milestone.md +166 -0
  247. package/workflows/new-project.md +213 -0
  248. package/workflows/next.md +8 -0
  249. package/workflows/note.md +244 -0
  250. package/workflows/park.md +29 -0
  251. package/workflows/pause-work.md +34 -0
  252. package/workflows/plan-milestone-gaps.md +233 -0
  253. package/workflows/plan-phase.md +351 -0
  254. package/workflows/progress.md +8 -0
  255. package/workflows/queue.md +9 -0
  256. package/workflows/research-phase.md +327 -0
  257. package/workflows/reset-slice.md +39 -0
  258. package/workflows/resume-work.md +79 -0
  259. package/workflows/review.md +489 -0
  260. package/workflows/secure-phase.md +209 -0
  261. package/workflows/session-report.md +243 -0
  262. package/workflows/skip.md +29 -0
  263. package/workflows/state.md +7 -0
  264. package/workflows/stats.md +170 -0
  265. package/workflows/thread.md +214 -0
  266. package/workflows/triage.md +9 -0
  267. package/workflows/ui-phase.md +246 -0
  268. package/workflows/ui-review.md +222 -0
  269. package/workflows/undo-task.md +42 -0
  270. package/workflows/undo.md +55 -0
  271. package/workflows/unpark.md +29 -0
  272. package/workflows/validate-phase.md +231 -0
  273. package/workflows/verify-work.md +83 -0
@@ -0,0 +1,212 @@
1
+ ---
2
+ command: np:add-backlog
3
+ description: Add a 999.x backlog item to ROADMAP.md. Uses lib/roadmap.cjs.addBacklogEntry (file-locked) to append to the synthetic "backlog" milestone. Creates .nubos-pilot/phases/999.X-<slug>/.gitkeep. One atomic docs commit.
4
+ ---
5
+
6
+ # np:add-backlog
7
+
8
+ Implements UTIL-05c. Mints a new entry in the synthetic `backlog`
9
+ milestone (id: `backlog`) using 999.x numbering. Unlike normal phases,
10
+ backlog items live outside the active milestone sequence — they are
11
+ the parking lot for "not-ready-to-plan" ideas that still deserve a
12
+ home in the roadmap.
13
+
14
+ The authoritative numbering and ROADMAP/roadmap.yaml update are
15
+ performed inside `lib/roadmap.cjs.addBacklogEntry` (landed in
16
+ Plan 10-01-T05). That helper is file-locked via `_mutate()` so two
17
+ parallel invocations serialise on the same 999.x counter (T-10-05-04
18
+ is accepted because the lock resolves the race inside the mutator).
19
+ The preview number shown to the user is computed OUTSIDE the lock and
20
+ is advisory only — the authoritative number comes back in the
21
+ helper's return value.
22
+
23
+ This is a pure-CRUD workflow — no agent spawn, no resolve-model, no
24
+ metrics record. The `workflow-missing-metrics` lint in
25
+ `bin/check-workflows.cjs` only fires on `Task(` / `Spawn agent=` sites,
26
+ so CRUD-only workflows are exempt (Pitfall 9 resolution from
27
+ Plan 10-05). Interactive prompts route through
28
+ `node np-tools.cjs askuser --json` per INST-03.
29
+
30
+ ## Initialize
31
+
32
+ ```bash
33
+ TITLE="$*"
34
+ if [[ -z "$TITLE" ]]; then
35
+ echo "Usage: /np:add-backlog <title>" >&2
36
+ exit 2
37
+ fi
38
+ ```
39
+
40
+ ## Compute Preview
41
+
42
+ Info-only preview — the preview number is NOT used as the commit
43
+ subject. The authoritative 999.X is assigned inside the lock and
44
+ returned in `RESULT` below.
45
+
46
+ ```bash
47
+ NEXT_NUMBER=$(node np-tools.cjs phase next-decimal 999 --raw)
48
+ SLUG=$(node np-tools.cjs generate-slug "$TITLE" --raw)
49
+ if [[ -z "$SLUG" ]]; then
50
+ echo "Error: title produced no slug-safe characters." >&2
51
+ exit 1
52
+ fi
53
+ echo "Will add backlog item: ${NEXT_NUMBER} — ${TITLE}"
54
+ ```
55
+
56
+ ## Confirm
57
+
58
+ ```bash
59
+ CHOICE=$(node np-tools.cjs askuser --json '{
60
+ "type": "select",
61
+ "header": "Backlog Item Preview",
62
+ "question": "Add backlog item '"${NEXT_NUMBER}"' — '"${TITLE}"'?",
63
+ "options": [
64
+ {"label": "Yes — append to ROADMAP + create phase dir", "description": "One atomic docs commit (ROADMAP.md + roadmap.yaml + .gitkeep)."},
65
+ {"label": "Cancel", "description": "Exit without changes."}
66
+ ]
67
+ }')
68
+ case "$CHOICE" in
69
+ "Cancel"*) exit 0 ;;
70
+ esac
71
+ ```
72
+
73
+ ## Append to ROADMAP
74
+
75
+ The real append happens through `lib/roadmap.cjs.addBacklogEntry`
76
+ which owns (1) input validation (500-char cap, YAML-separator reject),
77
+ (2) the file lock, and (3) the 999.X numbering computed inside the
78
+ mutator. The helper returns `{backlog_number, backlog_slug}`; we use
79
+ those values — NOT the preview values — for the phase directory and
80
+ commit subject.
81
+
82
+ ```bash
83
+ RESULT=$(node -e "const r=require('./lib/roadmap.cjs').addBacklogEntry(process.argv[1]); process.stdout.write(JSON.stringify(r));" "$TITLE")
84
+ BACKLOG_NUMBER=$(echo "$RESULT" | jq -r '.backlog_number')
85
+ BACKLOG_SLUG=$(echo "$RESULT" | jq -r '.backlog_slug')
86
+ ```
87
+
88
+ T-10-05-03 (description-breaks-YAML) is mitigated inside
89
+ `addBacklogEntry`: it rejects descriptions containing the YAML
90
+ separator pattern and caps length at 500 chars, then re-parses
91
+ roadmap.yaml inside the lock to validate the post-mutation document.
92
+
93
+ ## Create Phase Dir Stub
94
+
95
+ The backlog phase gets an empty `.gitkeep` directory so
96
+ `/np:discuss-phase 999.X` and `/np:plan-phase 999.X` have a place to
97
+ write CONTEXT/RESEARCH/PLAN artefacts when the idea graduates from
98
+ parking lot to active planning.
99
+
100
+ ```bash
101
+ STATE_DIR=$(node -e "console.log(require('./lib/core.cjs').projectStateDir(process.cwd()))")
102
+ PHASE_DIR="${STATE_DIR}/phases/${BACKLOG_NUMBER}-${BACKLOG_SLUG}"
103
+ mkdir -p "$PHASE_DIR"
104
+ touch "${PHASE_DIR}/.gitkeep"
105
+ ```
106
+
107
+ ## Commit
108
+
109
+ Route through `node np-tools.cjs commit` so
110
+ `lib/git.cjs.assertCommittablePaths()` validates each path before
111
+ `git add`. ROADMAP.md (rendered), roadmap.yaml (canonical source), and
112
+ the phase-dir `.gitkeep` land together as a single atomic unit per
113
+ ADR-0004.
114
+
115
+ ```bash
116
+ node np-tools.cjs commit "docs(10): add backlog item ${BACKLOG_NUMBER} — ${TITLE}" \
117
+ --files "${STATE_DIR}/ROADMAP.md" "${STATE_DIR}/roadmap.yaml" "${PHASE_DIR}/.gitkeep"
118
+ ```
119
+
120
+ ## Report
121
+
122
+ ```
123
+ Backlog item added: ${BACKLOG_NUMBER} — ${TITLE}
124
+ Directory: ${PHASE_DIR}/
125
+
126
+ This item lives in the backlog parking lot.
127
+ Use /np:discuss-phase ${BACKLOG_NUMBER} to explore it further.
128
+ ```
129
+
130
+ ## Scope Guardrail
131
+
132
+ <scope_guardrail>
133
+ **Do:**
134
+ - Use `lib/roadmap.cjs.addBacklogEntry` (file-locked + atomic
135
+ YAML+MD write) — it is the single sanctioned mutator for the
136
+ synthetic `backlog` milestone.
137
+ - Use `node np-tools.cjs phase next-decimal 999 --raw` for the
138
+ preview number ONLY. The authoritative number comes from
139
+ `addBacklogEntry`'s return value (re-computed inside the lock).
140
+ - Commit ROADMAP.md + roadmap.yaml + phase-dir `.gitkeep` together
141
+ as a single atomic unit per ADR-0004.
142
+ - Route the commit through `node np-tools.cjs commit` for
143
+ `lib/git.cjs.assertCommittablePaths()` validation.
144
+ - Confirm via `askuser` Pattern S-3 before the mutation — the
145
+ roadmap.yaml write is visible in git history forever.
146
+
147
+ **Don't:**
148
+ - Hand-edit ROADMAP.md. The synthetic backlog milestone renders via
149
+ `lib/roadmap-render.cjs` (Plan 10-01-T05); direct edits will be
150
+ overwritten on the next render pass.
151
+ - Use the preview number as the final commit subject. A concurrent
152
+ `/np:add-backlog` may race and claim the same number; only the
153
+ lock-returned `BACKLOG_NUMBER` is authoritative.
154
+ - Invoke host-specific prompt tools directly (the BARE_ASKUSER lint
155
+ in `bin/check-workflows.cjs` blocks them) — always route through
156
+ `node np-tools.cjs askuser --json '…'`.
157
+ - Add a `metrics record` block. There is no Task/Spawn site here;
158
+ Pitfall 9 / `workflow-missing-metrics` is exempt.
159
+ </scope_guardrail>
160
+
161
+ ## Output
162
+
163
+ - `.nubos-pilot/ROADMAP.md` — updated via
164
+ `lib/roadmap-render.cjs` to include the new 999.X entry under
165
+ the synthetic `## Backlog` H2 section (Plan 10-01-T05).
166
+ - `.nubos-pilot/roadmap.yaml` — canonical source-of-truth with the
167
+ new phase appended to the `backlog` milestone's `phases:` array.
168
+ - `.nubos-pilot/phases/999.X-<slug>/.gitkeep` — empty stub so
169
+ subsequent `/np:discuss-phase 999.X` invocations have a working
170
+ directory.
171
+ - One atomic git commit
172
+ `docs(10): add backlog item 999.X — <title>` containing the three
173
+ files above (ADR-0004).
174
+
175
+ ## Success Criteria
176
+
177
+ - [ ] Title validated (non-empty) before any roadmap read.
178
+ - [ ] Preview number generated via
179
+ `node np-tools.cjs phase next-decimal 999 --raw` — info only.
180
+ - [ ] Confirmation via `askuser` Pattern S-3 before mutation.
181
+ - [ ] Authoritative 999.X comes from
182
+ `lib/roadmap.cjs.addBacklogEntry` return value (NOT the
183
+ preview number).
184
+ - [ ] Phase directory created at
185
+ `${STATE_DIR}/phases/${BACKLOG_NUMBER}-${BACKLOG_SLUG}/` with
186
+ `.gitkeep` stub.
187
+ - [ ] Single atomic commit via `np-tools.cjs commit` containing
188
+ ROADMAP.md + roadmap.yaml + `.gitkeep`.
189
+ - [ ] Lint clean under `bin/check-workflows.cjs` — no BARE_ASKUSER
190
+ violations and no DIRECT_READ pattern matches for the project
191
+ state directory.
192
+
193
+ ## Related Workflows
194
+
195
+ - **`/np:add-todo <title>`** — smaller-scope pending todo capture
196
+ with STATE.md counter increment. Use when the idea is actionable
197
+ within a current plan.
198
+ - **`/np:note [--global] <text>`** — zero-friction free-form capture
199
+ with no ROADMAP mutation. Use when the idea isn't yet scoped.
200
+ - **`/np:discuss-phase 999.X`** — explore a backlog item
201
+ interactively to graduate it from parking-lot to active planning.
202
+ - **`/np:plan-phase 999.X`** — produce a CONTEXT/RESEARCH/PLAN stack
203
+ for a backlog item once it is ready for implementation.
204
+
205
+ ## Design Notes
206
+
207
+ Numbering + roadmap mutation run through
208
+ `lib/roadmap.cjs.addBacklogEntry` (Plan 10-01-T05). The lib-level
209
+ helper is file-locked and touches both the canonical `roadmap.yaml`
210
+ AND the rendered ROADMAP.md atomically — ROADMAP.md is rendered
211
+ output, not source-of-truth. The `.gitkeep` phase-dir stub keeps the
212
+ working directory legible before planning lands.
@@ -0,0 +1,69 @@
1
+ ---
2
+ command: np:add-tests
3
+ description: Persist Pass-SCs from VERIFICATION.md as node:test UAT blocks in test/uat/phase-<padded>-<slug>.test.cjs. Sentinel-preserving (D-20, Pitfall 8).
4
+ ---
5
+
6
+ # /np:add-tests
7
+
8
+ <objective>
9
+ After `/np:verify-work` emits VERIFICATION.md with SC classifications,
10
+ convert each Pass-SC into a runnable `node:test` case as a UAT regression
11
+ suite. User-authored tests outside the `>>> np:add-tests begin … <<< end`
12
+ sentinels survive regeneration.
13
+ </objective>
14
+
15
+ ## Initialize
16
+
17
+ ```bash
18
+ PHASE="$1"
19
+ INIT=$(node np-tools.cjs init add-tests "$PHASE")
20
+ ```
21
+
22
+ Parse: `phase`, `target_path`, `verification_path`, `pass_cases[]`,
23
+ `skip_cases[]`. Target path is
24
+ `<pkgRoot>/test/uat/phase-<padded>-<slug>.test.cjs`.
25
+
26
+ ## Execution
27
+
28
+ Emit/merge the Sentinel block:
29
+
30
+ ```bash
31
+ node np-tools.cjs init add-tests emit "$PHASE"
32
+ ```
33
+
34
+ Smoke-run the generated file to catch syntax errors early:
35
+
36
+ ```bash
37
+ node --test "$(echo "$INIT" | node -e "process.stdin.on('data', d => console.log(JSON.parse(d).target_path))")"
38
+ ```
39
+
40
+ ## Meta-commit
41
+
42
+ UAT tests are a PHASE artifact, not a TASK artifact, so ADR-0004
43
+ atomic-per-task does not apply — per D-19 this is a phase-level meta
44
+ commit. Scope it tightly to the UAT file only (never `git add .`):
45
+
46
+ ```bash
47
+ TARGET=$(echo "$INIT" | node -e "process.stdin.on('data', d => console.log(JSON.parse(d).target_path))")
48
+ git add "$TARGET"
49
+ git commit -m "docs(${PHASE}): persist UAT from verification"
50
+ ```
51
+
52
+ ## Scope Guardrail
53
+
54
+ **Do:**
55
+ - Render only the sentinel-bounded block; preserve everything outside.
56
+ - Use `test.skip(..., { todo: ... })` for Fail/Defer cases so the suite
57
+ tracks them without failing CI.
58
+ - `git add <target>` — single explicit path.
59
+
60
+ **Don't:**
61
+ - Overwrite user-authored tests outside the sentinels.
62
+ - Commit the VERIFICATION.md and the UAT file together (separate commits;
63
+ VERIFICATION.md is committed by `/np:verify-work`).
64
+
65
+ ## Output
66
+
67
+ - `test/uat/phase-<padded>-<slug>.test.cjs` with the sentinel-bounded
68
+ block updated.
69
+ - Meta-commit `docs(<padded>): persist UAT from verification`.
@@ -0,0 +1,222 @@
1
+ ---
2
+ command: np:add-todo
3
+ description: Capture a pending todo to .nubos-pilot/todos/pending/YYYY-MM-DD-<slug>.md; increments STATE.md pending_todos count via lib/state.cjs.mutateState single-writer lock. One atomic docs commit. No agent spawn.
4
+ ---
5
+
6
+ # np:add-todo
7
+
8
+ Implements UTIL-05a. Captures a free-form idea, task, or issue that
9
+ surfaces mid-session as a structured
10
+ pending todo so the originating workflow can continue without losing
11
+ context. The todo lives under `.nubos-pilot/todos/pending/` and the
12
+ pending-todo counter in STATE.md is bumped via the single-writer lock
13
+ in `lib/state.cjs.mutateState` (D-20 invariant).
14
+
15
+ This is a pure-CRUD workflow — no agent spawn, no resolve-model, no
16
+ metrics record. The `workflow-missing-metrics` lint in
17
+ `bin/check-workflows.cjs` only fires on `Task(` / `Spawn agent=` sites,
18
+ so CRUD-only workflows are exempt (Pitfall 9 resolution from
19
+ Plan 10-05). All interactive prompts route through
20
+ `node np-tools.cjs askuser --json` per INST-03.
21
+
22
+ ## Initialize
23
+
24
+ ```bash
25
+ DESCRIPTION="$*"
26
+ if [[ -z "$DESCRIPTION" ]]; then
27
+ echo "Usage: /np:add-todo <description>" >&2
28
+ exit 2
29
+ fi
30
+
31
+ INIT=$(node np-tools.cjs init add-todo "$DESCRIPTION")
32
+ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
33
+
34
+ SLUG=$(echo "$INIT" | jq -r '.slug')
35
+ DATE=$(echo "$INIT" | jq -r '.date')
36
+ TIMESTAMP=$(echo "$INIT" | jq -r '.timestamp')
37
+ PENDING_DIR=$(echo "$INIT" | jq -r '.pending_dir')
38
+ STATE_PATH=$(echo "$INIT" | jq -r '.state_path')
39
+ TODO_PATH="${PENDING_DIR}/${DATE}-${SLUG}.md"
40
+ ```
41
+
42
+ Extract from init JSON: `commit_docs`, `date`, `timestamp`, `slug`,
43
+ `todo_count`, `todos_dir_exists`, `pending_dir`, `state_path`. The
44
+ init handler sanitises the slug through `lib/phase.cjs.phaseSlug`
45
+ (strips to `[a-z0-9-]` only; T-10-05-01 filename-injection
46
+ mitigation) and validates the description length (<= 500 chars) before
47
+ any filesystem write occurs.
48
+
49
+ ## Create Pending Dir
50
+
51
+ ```bash
52
+ mkdir -p "$PENDING_DIR"
53
+ ```
54
+
55
+ The directory is created idempotently; no-op if it already exists.
56
+
57
+ ## Duplicate Check
58
+
59
+ If a todo with this `DATE-SLUG` already exists in `pending/`,
60
+ let the user resolve the collision via `askuser` Pattern S-3. The
61
+ prompt surfaces four options: re-run (overwrite), view existing,
62
+ skip (keep both), or rename-with-counter (append `-2`, `-3`, etc.).
63
+
64
+ ```bash
65
+ if [[ -f "$TODO_PATH" ]]; then
66
+ CHOICE=$(node np-tools.cjs askuser --json '{
67
+ "type": "select",
68
+ "header": "Duplicate todo",
69
+ "question": "A todo already exists at '"${TODO_PATH}"'. What would you like to do?",
70
+ "options": [
71
+ {"label": "Re-run — overwrite existing todo", "description": "Replaces the current todo body."},
72
+ {"label": "View — display the existing todo and exit", "description": "No changes."},
73
+ {"label": "Skip — keep existing and exit", "description": "Leaves the file untouched."},
74
+ {"label": "Rename — append -2/-3 counter to filename", "description": "Writes a new file beside the existing one."}
75
+ ]
76
+ }')
77
+ case "$CHOICE" in
78
+ "View"*) cat "$TODO_PATH"; exit 0 ;;
79
+ "Skip"*) exit 0 ;;
80
+ "Rename"*)
81
+ i=2
82
+ while [[ -f "${PENDING_DIR}/${DATE}-${SLUG}-${i}.md" ]]; do i=$((i + 1)); done
83
+ TODO_PATH="${PENDING_DIR}/${DATE}-${SLUG}-${i}.md"
84
+ ;;
85
+ esac
86
+ fi
87
+ ```
88
+
89
+ ## Write Todo File
90
+
91
+ Use the `Write` tool (not a bash heredoc) to create `$TODO_PATH` with
92
+ the following frontmatter + body. The agent invokes the `Write` tool
93
+ directly — this is documented here as the contract, not executed as a
94
+ shell step.
95
+
96
+ ```markdown
97
+ ---
98
+ title_short: <first 100 chars of DESCRIPTION, single line>
99
+ created: <TIMESTAMP>
100
+ status: pending
101
+ ---
102
+
103
+ <DESCRIPTION>
104
+ ```
105
+
106
+ Specifically: `title_short` = the first 100 chars of `$DESCRIPTION`
107
+ flattened to a single line (newlines replaced with spaces) so the
108
+ frontmatter stays parseable even when the raw description contains
109
+ YAML metacharacters or multiple lines, `created` = `$TIMESTAMP`
110
+ (init-supplied ISO-8601), `status` always `pending`. The body carries
111
+ the full raw description verbatim so the file is self-contained when
112
+ read weeks later. This mirrors the `note.md` pattern (truncated
113
+ frontmatter field + full body) and pairs with the
114
+ `add-todo-invalid-description` YAML-separator guard in
115
+ `bin/np-tools/add-todo.cjs._buildPayload`. Do **not** include
116
+ `status: completed` or any other status here — the completion flow
117
+ lives in a separate workflow.
118
+
119
+ ## Update STATE.md
120
+
121
+ STATE.md is mutated through `lib/state.cjs.mutateState` which wraps
122
+ `withFileLock` (D-20 single-writer invariant, T-10-05-06 mitigation).
123
+ The node one-liner is the sanctioned surface; direct filesystem
124
+ reads of the project state directory from this workflow would bypass
125
+ the lock and are explicitly forbidden by the check-workflows lint.
126
+
127
+ ```bash
128
+ node -e "require('./lib/state.cjs').mutateState(function (doc) { doc.frontmatter.pending_todos = (doc.frontmatter.pending_todos || 0) + 1; return doc; });"
129
+ ```
130
+
131
+ The mutator increments the `pending_todos` counter on the STATE.md
132
+ frontmatter. The lock serialises concurrent writers (two parallel
133
+ `/np:add-todo` invocations converge on the correct count).
134
+
135
+ ## Commit
136
+
137
+ Route through `node np-tools.cjs commit` so
138
+ `lib/git.cjs.assertCommittablePaths()` validates the paths before
139
+ `git add` (path-traversal guard from Plan 10-01-T04).
140
+
141
+ ```bash
142
+ node np-tools.cjs commit "docs(10): add todo — ${SLUG}" --files "$TODO_PATH" "$STATE_PATH"
143
+ ```
144
+
145
+ Both the new todo file and STATE.md land in a single atomic commit per
146
+ ADR-0004 (one commit per unit).
147
+
148
+ ## Report
149
+
150
+ ```
151
+ Todo saved: $TODO_PATH
152
+
153
+ Title: $DESCRIPTION
154
+ Status: pending
155
+ Created: $TIMESTAMP
156
+
157
+ Pending todo count bumped via lib/state.cjs.mutateState.
158
+ Use /np:next to surface this todo in the next-step picker.
159
+ ```
160
+
161
+ ## Scope Guardrail
162
+
163
+ <scope_guardrail>
164
+ **Do:**
165
+ - Always go through `lib/state.cjs.mutateState` for STATE.md updates
166
+ (D-20 single-writer lock; T-10-05-06 mitigation).
167
+ - Use the `Write` tool for the new markdown file — never a bash
168
+ heredoc or `echo >`.
169
+ - Route the final commit through `node np-tools.cjs commit` so
170
+ `lib/git.cjs.assertCommittablePaths()` runs the gitignore-guard.
171
+ - Derive the slug via `node np-tools.cjs init add-todo` (filename
172
+ sanitisation, T-10-05-01 mitigation) — not via ad-hoc `sed`.
173
+ - Commit todo file + STATE.md together as a single atomic unit.
174
+
175
+ **Don't:**
176
+ - Invoke host-specific prompt tools directly (the BARE_ASKUSER lint in
177
+ `bin/check-workflows.cjs` blocks them) — always route through
178
+ `node np-tools.cjs askuser --json '…'`.
179
+ - Read STATE.md via raw filesystem calls (DIRECT_READ lint blocks
180
+ those patterns) — let `mutateState` handle the lock.
181
+ - Add a `metrics record` block. There is no Task/Spawn site in this
182
+ workflow, so Pitfall 9 / the `workflow-missing-metrics` lint is
183
+ exempt.
184
+ - Touch the completed-todos subtree — completion is a separate
185
+ workflow concern.
186
+ </scope_guardrail>
187
+
188
+ ## Output
189
+
190
+ - `.nubos-pilot/todos/pending/YYYY-MM-DD-<slug>.md` — new todo file
191
+ with `title / created / status: pending` frontmatter and the
192
+ description as body text.
193
+ - `.nubos-pilot/STATE.md` — `pending_todos` frontmatter counter
194
+ incremented via `mutateState`.
195
+ - One atomic git commit `docs(10): add todo — <slug>` containing
196
+ both files (ADR-0004).
197
+
198
+ ## Success Criteria
199
+
200
+ - [ ] Description validated (non-empty, <= 500 chars) via the init
201
+ handler before any filesystem write.
202
+ - [ ] Slug derived via `phaseSlug` so only `[a-z0-9-]` enter the
203
+ filename (T-10-05-01 mitigation).
204
+ - [ ] Pending todo directory created idempotently.
205
+ - [ ] Duplicate collisions resolved via `askuser` Pattern S-3
206
+ (Re-run / View / Skip / Rename-with-counter).
207
+ - [ ] Todo file written via the `Write` tool with valid frontmatter.
208
+ - [ ] STATE.md `pending_todos` counter incremented via
209
+ `lib/state.cjs.mutateState` (D-20 single-writer lock).
210
+ - [ ] Both files committed atomically via `np-tools.cjs commit`.
211
+ - [ ] Lint clean under `bin/check-workflows.cjs` — no BARE_ASKUSER
212
+ violations and no DIRECT_READ pattern matches for the project
213
+ state directory.
214
+
215
+ ## Related Workflows
216
+
217
+ - **`/np:note <text>`** — zero-friction free-form capture (no STATE
218
+ mutation, no todo semantics). Use when the idea isn't yet actionable.
219
+ - **`/np:add-backlog <title>`** — larger-scope capture for ideas that
220
+ deserve a full backlog phase (`999.x` in ROADMAP.md).
221
+ - **`/np:next`** — surfaces the next actionable item; a pending todo
222
+ can be the pointer when no active plan has a runnable task.