CLI Commands
Every subcommand exposed by np-tools.cjs, mirrored from bin/np-tools/_commands.cjs (the canonical registry).
Dispatch has two layers:
init <workflow>— orchestrator workflows. Calls a registered handler inbin/np-tools/<name>.cjs(plan-milestone,execute-milestone,discuss-phase,new-project, …). An unknown init workflow returnsunknown-init-workflowwith exit code 1.- Top-level commands — utility and leaf commands (
commit-task,checkpoint,metrics,doctor, …).
Output is JSON; payloads above 16 KB are spilled to .nubos-pilot/.tmp/init-<workflow>-<pid>-<rand>.json and the path emitted as @file:<path>.
Commands by category
Planning
| Command | Description |
|---|---|
agent-skills | Print agent_skills config for a given subagent |
archive-project | Move current .nubos-pilot/ project to archive/<slug>-<YYYYMMDD>/ (status|do|list|read) |
derive-tier | Advisory: derive a suggested executor tier (haiku|sonnet|opus) from a task's observable signals (files_modified + risk keywords). Decider stays the planner. ADR-0013. |
discuss-phase | Adaptive milestone-context interview (writes M<NNN>-CONTEXT.md) |
discuss-project | Adaptive project-context interview (writes PROJECT.md decisions) |
new-milestone | Append a new milestone (M<NNN>) to an existing project |
new-project | Greenfield project init (PROJECT.md + REQUIREMENTS.md + M001 milestone) |
phase-meta | Read roadmap.yaml phase fields as JSON (supports --field NAME and --length for arrays) |
plan-lint | Mechanical Trust-Layer linter for PLAN.md (verify-command + parallel-race + over-specification + pattern-claim). ADR-0019, ADR-0032 |
plan-milestone | Plan a milestone: scaffolds slices + tasks |
propose-milestones | Re-plan all not-yet-done milestones: AI proposes add/update/remove from PROJECT.md + REQUIREMENTS.md |
research-phase | Milestone-level research (WebFetch + MCP; offline fallback) |
researcher-reconcile | Researcher-swarm reconciliation (ADR-0018). Verbs: parse-spawn --file | prepare <N> | gate <N>. Reads per-spawn outputs, applies reasoning-trace classification, surfaces contested decisions, hard-gates on agreement_score / contested_count. |
rollup | Derive slice + milestone status from task states and sync roadmap.yaml. Usage: rollup [<N>|all] | rollup inspect <N>. Never writes a terminal milestone status — that stays with verify-work. |
update-phase-meta | Update roadmap.yaml phase fields (name/goal/requirements/success_criteria) via JSON patch |
Execution
| Command | Description |
|---|---|
add-tests | Persist VERIFICATION Pass-cases as node:test UAT (Sentinel-preserving) |
checkpoint | Per-task crash-safety checkpoint CRUD (start/transition/touch/show) |
commit-task | Atomic per-task git commit via lib/git.cjs |
execute-milestone | Wave-based milestone execution — slice by slice, tasks parallel within a slice |
learning-log | Persist a learning to the local store (or MCP adapter when configured) |
learnings | Stop-hook continuous-learning capture (ADR-0010). Verbs: capture (rate-limited; spawns headless np-learnings-extractor over the turn diff) | reset (clears stop-streak) | run-extract (background worker). Gated by learnings.auto_capture. |
loop-audit-tool-use | Record/read the tool-use audit per spawn (Completeness Rule 9 mechanical check) |
loop-evaluate | Run evaluateLoop over critic outputs JSON; emit next_action + findings + routing |
loop-preflight | Per-task pre-flight cache lookup (ADR-0010 Step 1) — short-circuits the Researcher-Schwarm on hit |
loop-run-round | Drive the per-task Nubosloop state machine — phases: preflight | post-executor | post-critics | commit | stuck |
loop-state-read | Read the per-task Nubosloop state from the checkpoint (round, last_action, findings) |
loop-state-record | Atomically merge a partial Nubosloop state update into the task checkpoint |
loop-stuck | Mark a task as stuck (writes loop-state + flips checkpoint status to stuck) |
park | Mark task status parked (lifecycle CRUD) |
pause-work | Stamp STATE.session.stopped_at + resume_file for explicit handoff |
reset-slice | Discard in-flight task: restore working tree from HEAD, drop checkpoint, clear STATE.current_task |
resume-work | Classify session state (resume | orphan | clean) from STATE + checkpoints |
skill-audit | Skill-bar consultation audit (counterpart to the Rule-9 search audit). Verbs: expect --task --skills (orchestrator records injected skills) | ack --task --skill (executor stamps a consulted skill) | findings --task [--round] (list unmet bars). An unconsulted injected skill becomes a skill-bar-unconsulted finding that routes back to the executor. |
skip | Mark task status skipped (lifecycle CRUD) |
slice-plan | Evaluate conditional slice edges for a milestone (ADR-0028). Verbs: plan <N> | lint. Decisions are three-valued — run | skip | wait — because a slice whose predecessor merely has not finished is waiting, not skipped. An unresolvable condition is an error, never a run. Requires roadmap schema_version 3 for any slice carrying a when. |
spawn-headless | Spawn an agent as a headless claude -p subprocess (ADR-0010 §L6); writes stdout to --output-path and returns exit code |
spawn-offhost | Run an agent routed to an openai-compat provider (Ollama/OpenAI/Grok) as a one-shot tool-use loop (ADR-0021). Args: --agent --task|--task-file [--allow-bash] [--read-only]. Preflights the endpoint, records metrics. |
task-verify-cmd | Print the executable <verify> command lines of a task plan (one per line, or --json). The orchestrator runs these in execute-phase Step 4. |
undo | Revert every task commit of a milestone or slice via git revert (no history rewrite) |
undo-task | Revert a single task commit and reset task status to pending |
unpark | Return a parked task to pending (lifecycle CRUD) |
verify-reliability | pass@k reliability: fold k verify-run exit codes into pass@1/pass@k/flaky + an aggregate exit code (pass^k) for loop-run-round. Opt-in via loop.verify_runs. |
verify-work | Two-pass goal-backward verification (milestone-level VERIFICATION.md) |
worktree-create | Create an isolated git worktree for a slice (branch np/<mid>-<sid> off current HEAD) under .nubos-pilot/worktrees/ |
worktree-ff-merge | Fast-forward merge a slice branch back to its base (fails hard on non-FF) |
worktree-list | List all nubos-pilot-managed slice worktrees (np/<mid>-<sid> only) as JSON |
worktree-remove | Remove a slice worktree + delete its branch (--force / --keep-branch) |
Review
| Command | Description |
|---|---|
close-project | Aggregate verification of every milestone; writes PROJECT-SUMMARY.md + sets project_status=completed |
gate-candidates | Cluster failed/reverted learnings into recurring failure classes worth encoding as a mechanical gate instead of a prompt instruction |
output-lint | Mechanical output-artifact linter (frontmatter + body + cross-field invariants). Verbs: check | prompt | list. Schemas in lib/schemas/. Hard-gates verify-work, validate-phase. ADR-0017 |
pressure-eval | Behavioural compliance harness (ADR-0024). Verbs: lint | list | coverage | prompt | evaluate | report. Scores an agent response against a pressure fixture that stacks >=3 pressures and forces a discrete choice; a pass requires the compliant choice AND a citation of the rule. Offline verbs never call a model — report is the model-swap regression gate. |
scan | Native dependency, secret and misconfiguration scanner (ADR-0031). Verbs: all | inventory | advisory | secrets | misconfig | license | sbom | db-status. Deterministic, offline, no model call. --json for machine output, --fail-on high|critical to gate a CI step. |
security | In-session security review hook backend (ADR-0020). Verbs: session-start | baseline | scan | review | commit | run-review. Reads the Claude Code hook payload via --stdin; non-blocking, report-once, independent reviewer spawn. |
Capture
| Command | Description |
|---|---|
add-todo | Capture a pending todo to .nubos-pilot/todos/pending/ + increment STATE count |
handoff-list | List handoffs (JSON array); filter with --for AGENT, --milestone M<NNN>, --status STATUS, --global |
handoff-read | Read a single handoff by id (returns frontmatter + body as JSON) |
handoff-status | Update a handoff status (open|read|acted|archived) |
handoff-write | Write an agent-to-agent handoff note (milestone-scoped by default, global without --milestone) |
memory-add | Add a single record to vector memory (--type, --title, --body / --body-file, optional --tags / --provenance / --phase / --id / --skip-if-disabled) |
memory-index | Bulk-index records into vector memory (--records JSON or --records-file JSONL). Opt-in via memory.enabled=true. ADR-0014 |
messages-archive | Move an inbox message to archive/; refuses request+expects_reply without prior response |
messages-inbox | List unread messages addressed to an agent (filterable by --kind, --since, --task) |
messages-send | Send addressed inter-agent message (request|response|notify) to .nubos-pilot/messages/inbox/<to>/. ADR-0015 |
messages-thread | Print full reply-chain for a message id (causal order) |
resume-doc | Session handoff document (ADR-0025). Verbs: write | lint | read | status | ack | learnings. Six-section re-entry brief written at a session boundary; failed_approaches is mandatory because it is the one section git cannot reconstruct. status returns gate none|blocked|clear — resume-work refuses code work while blocked. Refuses secret values; variable names are fine. |
simplify-debt | Economy-debt ledger CRUD — record deferred simplifications so "later" does not become "never". Verbs: add --file --line --category --note | list [--status open|resolved|all] [--json] | resolve <id>. Categories mirror the four Economy critic routes; manual twin of /np:simplify-review. |
state-incr | Increment a whitelisted STATE.md counter (e.g. pending_todos) under withFileLock |
Install
| Command | Description |
|---|---|
doctor | 16-check install-integrity scan (--fix for auto-safe fixes). Exit 1 on error-severity findings. |
isolation | Execution isolation tiers (ADR-0029). Verbs: status | describe <tier> | probe | wrap -- <cmd>. Three tiers: direct (none — the agent holds whatever the host CLI grants), worktree (version isolation only, ADR-0008; rights unchanged), container (rights isolation; project mounted, no network by default). A configured tier is never silently downgraded — an unusable container runtime refuses instead of falling back. |
scan-codebase | Initial deep codebase inventory → .nubos-pilot/codebase/ skill docs |
update-docs | Refresh stale module docs after code changes |
workspace-scan | Scan a workspace and emit inventory JSON (full result or --summary shape for /np:new-project) |
Utility
| Command | Description |
|---|---|
acp | Agent Client Protocol groundwork (ADR-0030). Verbs: status | initialize-request | negotiate. JSON-RPC 2.0 vocabulary, newline-delimited framing and the initialize handshake, with version negotiation that refuses an unsupported MAJOR rather than guessing. Stage is groundwork: no transport is wired into the spawn path and every client capability is off, because declaring one before its handler exists makes the agent wait on a reply that never comes. |
askuser | Capability-layer prompt wrapper (reads spec JSON, returns chosen label) |
commit | Atomic git commit wrapper with gitignore-guard |
config-get | Read value from .nubos-pilot/config.json by dotted key path |
context-stats | Aggregated context-budget stats (file counts + bytes per group, knowledge-index size) |
dashboard | One-shot console dashboard of milestones, slices, and tasks. Read-only; flags: --json, --no-color |
detect-runtime | Print detected runtime id (claude, codex, gemini, …) — reads config.json ∨ env ∨ default |
detect-stack | Print detected project stacks + their lint/typecheck commands — SSOT for stack-aware verification |
economy-mode | Resolve the Economy axis level (off|lite|full|ultra) from agents.economy (legacy agents.economy_critic honoured; default lite). Prints the mode, or --json for {mode,prevention,critic,ultra} gate flags. Single source for the execute-phase economy gate. |
elision-bench | Measure elision compression: deterministic fidelity (ratio + critical-line preservation + byte-exact reversibility) over a fixture corpus; --with-model adds answer-equivalence (raw vs compressed). --size <small|medium|large> runs a scaled corpus with a deterministic --holdout control group (--max-cases N) and an estimated token saving (--price-per-mtok <p> [--currency EUR] adds a cost estimate). --json, --tier <name> |
elision-get | Retrieve the original text behind a ⟦elided:<hash>⟧ compression marker. Reversible context compression (ADR-Elision). Positional <hash> or --hash; --json for envelope |
generate-slug | Slugify text via lib/layout.cjs.slugify |
graph-impact | Query the module dependency graph (.graph.json from np:scan-codebase): impact (transitive dependents), dependencies, cluster, cycle membership. Flags: --module <id> | --path <relpath> | --cycles |
help | List available commands |
init | Dispatcher init payload for workflows |
knowledge-index | Build BM25-light index over .nubos-pilot/**/*.md → .nubos-pilot/state/knowledge-index.json |
knowledge-search | Query the knowledge index; returns top-N JSON hits (rel_path + lines + score + preview). Inside a Nubosloop task pass --task <id> AND --agent <name> to record Rule 9 audit evidence; evidence is credited per agent, so omitting --agent leaves the audit unsatisfied |
knowledge-stats | Print knowledge-index size + grouping (auto-builds if missing) |
lang-directive | Print workflow language directive from config.response_language (SSOT) |
learning-list | List learnings sorted by occurrence (most-used first) |
learning-match | Query the learnings store for cached patterns matching a free-text query |
loop-metrics | Aggregate Nubosloop telemetry across all checkpoints (commits, stuck, route distribution) |
memory-query | Query vector memory by text; returns top-k JSON hits with score + record. Filter by --type, --phase, --tags |
memory-rebuild | Force full re-embed from records.jsonl; required after embedding-model change. ADR-0014 |
memory-stats | Print vector-memory stats (count, dim, model, schema_version, created_at) |
metrics | Record JSONL metrics entry (record | now | start-timestamp | end-timestamp) |
otlp-export | Export the milestone/slice/task/agent-spawn hierarchy as an OTLP span tree (ADR-0026). Verbs: dry-run | write --out | send | stats. Emits OTLP/HTTP JSON for Langfuse, an OpenTelemetry collector, or any OTLP backend — no bundled client, no daemon, no dependency. Span ids are derived from unit ids so a re-export updates one trace. send requires telemetry.otlp.enabled. |
render-template | Render a shipped template by name with --vars JSON (or --vars-file PATH) |
render-todo | Render slice TODO.md rollup (checkbox view of task statuses) for a slice full-id |
resolve-model | Resolve agent/tier to model alias or id (Tier×Profile matrix) |
roadmap-graph | Render roadmap.yaml as a dependency graph in Mermaid or Graphviz DOT (ADR-0027). Flags: --format mermaid|dot, --level milestone|slice|task, --direction TD|LR, --milestone N, --markdown, --out, --json. Draws milestone depends_on, task depends_on, and the serial slice order the executor enforces but roadmap.yaml only implies. Read-only — no verb writes roadmap.yaml. |
session-aggregate | Aggregate session metrics under withFileLock; reads pointer .last-session unless --since overrides |
session-pointer-write | Atomic write of .nubos-pilot/reports/.last-session under withFileLock (ISO-8601 UTC) |
session-snapshot-read | Print last session snapshot as JSON |
session-snapshot-write | Capture session snapshot (current_task + recent commits + open handoffs) for resume |
state | Print the current project state snapshot |
state-dir | Print project-state directory (.nubos-pilot) or a validated subdir via --subdir NAME |
stats | Aggregated project stats — json | bar | markdown (markdown labels follow config.response_language) |
template-path | Print absolute path to a package-shipped template by name (e.g. VALIDATION, milestone/CONTEXT) |
text-mode | Print whether text mode is active (config.workflow.text_mode ∨ CLAUDECODE) |
thread-resume | Bump a thread markdown on resume (status OPEN→IN_PROGRESS, refresh last_resumed) via atomic write |
The tables above are regenerated from bin/np-tools/_commands.cjs by scripts/generate-docs.cjs. To add a command, append an entry to that registry; the doc table picks it up on the next run.
Registry descriptions are one-line summaries. Where a command needs more detail, the dedicated reference or workflow page is authoritative. For example,
np:doctorlists all 12 integrity checks.
Milestone status: who writes what
Milestone and slice status in roadmap.yaml have exactly two writers, and the split is deliberate.
| Transition | Written by | Trigger |
|---|---|---|
milestone pending → in-progress | execute-milestone init, and the rollup | execution starts; any task leaves pending |
slice pending → in-progress → done | rollup (lib/rollup.cjs) | derived from the task states on disk |
milestone → verified / failed / deferred | verify-work only | SC verdicts in M<NNN>-VERIFICATION.md |
The rollup never sets a terminal milestone status. Terminal means "verification ran", so deriving it from task completion would let a milestone read as finished with nothing behind it — precisely what close-project's blocker gate exists to catch. A milestone whose slices are all done therefore stays in-progress until /np:verify-work classifies its success criteria; np-tools doctor surfaces that state as milestone-ready-for-verification.
The rollup runs on every task transition (hooked into setTaskStatus, so it covers commit-task, skip, park, unpark, undo, undo-task alike) and is idempotent. It is non-fatal: if roadmap.yaml cannot be written, the task transition still stands and the mismatch is logged. Repair drift with:
np-tools.cjs rollup <N> # one milestone
np-tools.cjs rollup all # every milestone
np-tools.cjs rollup inspect <N> # report without writingHow task states map to a slice
| Task states in the slice | Slice status |
|---|---|
all done / skipped (any mix) | done — a skipped task leaves no work behind, so an all-skipped slice completes with zero work done |
any in-progress, done, skipped or parked present | in-progress |
all pending | pending |
| any PLAN.md missing or without a status | never done — an unreadable task blocks completion rather than being ignored |
parked deliberately holds a slice open, so a fully parked slice reads in-progress indefinitely; doctor surfaces that as slice-fully-parked rather than the status vocabulary growing a "blocked" value.
The slice set comes from what roadmap.yaml declares, not from what exists on disk — a milestone declaring S001..S003 with only S001 scaffolded is not verification-ready.
Related doctor findings
| Finding | Meaning |
|---|---|
slice-status-drift | persisted slice status is behind the tasks on disk → np-tools rollup <N> |
milestone-status-drift | roadmap.yaml, M<NNN>-META.json and the SC verdicts disagree → verify-work sync-roadmap |
milestone-ready-for-verification | every slice is done, no VERIFICATION.md yet → /np:verify-work <N> |
milestone-terminal-with-open-work | milestone claims a terminal status while work reopened → the verification it points at is stale |
task-plan-unreadable | task directories exist whose PLAN.md is missing or has no status |
slice-fully-parked | every task in a slice is parked, so the slice can never complete on its own |
Closing and archiving a project
close-project close runs the whole closing sequence in the only order that works — summary, then project_status, then (optionally) archive, because the archiver moves PROJECT-SUMMARY.md and needs it written first.
np-tools.cjs close-project close [--archive] [--force] [--carry-over a,b | --no-carry-over] [--allow-unknown]| Flag | Effect |
|---|---|
--archive | Archive immediately after closing. Without it the project is closed but stays live. |
--force | Close past unresolved blockers. Recorded as forced: true plus the real blockers_at_archive in ARCHIVE.json — a forced close is never reported as a clean one. |
--carry-over a,b / --no-carry-over | Which paths are copied back out of the archive for the successor. Defaults to knowledge/learnings.json + knowledge/solutions. |
--allow-unknown | Archive despite unclassified state entries, listing them in the manifest as skipped_unknown. |
Both close and mark-completed refuse with close-project-blocked unless --force was given, writing nothing on refusal. Unknown flags and flags missing their value are rejected rather than ignored, so a typo cannot silently skip the archive.
A recorded project_status: completed authorizes archiving but no longer masks blockers: completion.complete stays blocker-based and honest, while the separate completion.archivable carries the authorization. A forced close is therefore still visible as forced: true plus the real blockers_at_archive in ARCHIVE.json.
Exit code on a failed archive. If closing succeeds but archiving fails, the command writes its full payload (closed: true, archived: false, archive_error) to stdout and exits non-zero. The close stands; only the archive is missing, and archive-project do picks up from there. Do not read the non-zero exit as a failed close.
What archiving moves
lib/archive.cjs classifies every top-level entry under .nubos-pilot/ into exactly one of two frozen lists, and refuses with archive-unknown-state-artifact on anything it does not recognise — an allowlist alone silently leaves new artefacts behind, which is how project-specific data used to leak into successor projects.
| Entries | |
|---|---|
| Archived (project content) | PROJECT.md, PROJECT-SUMMARY.md, REQUIREMENTS.md, RULES.md, ROADMAP.md, STATE.md, roadmap.yaml, milestones/, phases/, codebase/, references/, metrics/, notes/, checkpoints/, economy-debt/, messages/, threads/, handoffs/, todos/, reports/, knowledge/, session/ |
| Preserved (tool runtime, survives into the successor) | config.json, security-rules.json, prose-auth.json, archive/, state/, worktrees/, memory/, bin/, agents/, templates/, backups/, audit/, elision/, run/, plus every dot-entry |
Adding a new top-level artefact means adding it to one of the two lists; a test asserts that every state-dir path the source creates is classified, so an unclassified one fails the suite rather than leaking at archive time.
User-facing workflow aliases
Three slash-commands preserve older naming for continuity. They dispatch to milestone-scoped init commands:
| User-facing | Delegates to | Notes |
|---|---|---|
/np:plan-phase <N> | init plan-milestone init <N> + scaffolder | "phase" = milestone in the command name |
/np:execute-phase <N> [--verify-work] | init execute-milestone init <N> [--verify-work] + per-task dispatch | slice-by-slice, tasks parallel within slice; --verify-work chains /np:verify-work <N> on success |
/np:validate-phase <N> | Nyquist auditor → M<NNN>-VALIDATION.md | |
/np:close-project | init close-project + askuser blocker gate | project-level aggregate verification; writes PROJECT-SUMMARY.md and flips project_status: completed |
/np:architect-phase <N> | spawns np-architect → M<NNN>-ARCHITECTURE.md | optional, between research and planning |
/np:knowledge "<query>" | wraps knowledge-index + knowledge-search | local full-text search over project markdown |
/np:context-stats | wraps context-stats | localized markdown snapshot of the knowledge index |
