Appearance
State & Files
The Project-State tree under .nubos-pilot/ is the only place workflows write end-user data. Every file here either is the source of truth for some unit-type, or is a derived artifact regenerated from one.
Top-level layout
The full directory tree (every file, who produces it, who consumes it, mandatory vs optional) lives in Directory Layout reference. Top level at a glance:
.nubos-pilot/
├── PROJECT.md, REQUIREMENTS.md, RULES.md # source of truth
├── roadmap.yaml, STATE.md, config.json # source of truth (roadmap.yaml.project_status: active | completed)
├── PROJECT-SUMMARY.md # derived: regenerated by /np:close-project
├── milestones/M<NNN>/slices/S<NNN>/tasks/T<NNNN>/
├── state/ # ephemeral cache (gitignored)
├── handoffs/ # project-global agent handoffs
├── worktrees/ # opt-in per-slice git worktrees (gitignored)
├── todos/, notes/, threads/ # capture types
├── checkpoints/ # per-task crash-safety pointers
├── metrics/ # *.jsonl append-only
├── codebase/ # module docs from /np:scan-codebase
├── learnings/, solutions/ # carry over into successor projects by default
├── memory/ # opt-in vector store, ADR-0014
├── archive/<slug>-<YYYYMMDD>/ # archived predecessor projects, ADR-0016
├── .last-session, .install.lock, .tmp/Source of truth vs derived
| File | Source of truth | Derived |
|---|---|---|
roadmap.yaml | ✓ | |
PROJECT.md | ✓ | |
REQUIREMENTS.md | ✓ | |
RULES.md | ✓ | |
STATE.md | ✓ | |
config.json | ✓ | |
milestones/M<NNN>/M<NNN>-CONTEXT.md | ✓ (from /np:discuss-phase) | |
milestones/M<NNN>/slices/S<NNN>/S<NNN>-PLAN.md | ✓ (from planner) | |
milestones/M<NNN>/slices/S<NNN>/tasks/T<NNNN>/T<NNNN>-PLAN.md | scaffolded from <task> block in slice PLAN | |
milestones/M<NNN>/M<NNN>-PLAN-REVIEW.md | ✓ (append-only) | |
milestones/M<NNN>/M<NNN>-VERIFICATION.md | ✓ | |
milestones/M<NNN>/slices/S<NNN>/tasks/T<NNNN>/T<NNNN>-SUMMARY.md | ✓ (filled by executor) | |
milestones/M<NNN>/slices/S<NNN>/TODO.md | ✓ — rendered from task frontmatter by lib/todo.cjs::renderTodoMd | |
milestones/M<NNN>/handoffs/*.md | ✓ (append-on-write from handoff-write) | |
handoffs/*.md (project-global) | ✓ (same writer, no --milestone) |
Task PLAN files can be regenerated by /np:plan-phase <N> --repromote — the authoritative source is the slice PLAN's <task> blocks. TODO.md is purely derived: deleting it is safe; the next setTaskStatus call re-creates it.
Parser-mandatory files
Only two file shapes are parser-mandatory:
S<NNN>-PLAN.md— read by the planner / plan-checker / scaffolder. Must contain<task>blocks withid/depends_on/wave/tierattributes.T<NNNN>-PLAN.md— read bylib/tasks.cjs.loadTaskGraphand the executor. Must have valid frontmatter perTASK_REQUIRED_FIELDS.
Every other file is workflow-produced and read with ENOENT-tolerance; a missing file means "that step has not run yet". Full table in the Directory Layout reference.
Single-writer guarantee
Every workflow that mutates .nubos-pilot/ acquires a file lock through lib/core.cjs.withFileLock. The implementation:
- Uses
O_EXCLwrites to a<file>.locksidecar, atomic on every supported filesystem. - Embeds
pid,hostname, andacquiredAtin the lock payload for diagnostics. - Stale-detects locks older than 30 s from a different host and forcibly recovers.
- Registers a
process.on('exit')cleanup so a crashed process does not leave a stuck lock.
Concurrent workflow runs queue rather than race. There is no daemon to coordinate them; the lockfile is the only coordinator (ADR-0001).
Atomic writes
Every state mutation routes through atomicWriteFileSync(path, content):
write(tmp + .pid.rand.tmp) → renameSync(tmp, path)A crash mid-write leaves either the old content or the new content — never a half-written file.
Checkpoints
.nubos-pilot/checkpoints/<task-full-id>.json is the per-task crash-safety pointer (e.g. M001-S001-T0001.json). The executor transitions through pending → in-progress → verifying → pre-commit via np-tools.cjs checkpoint transition. On a successful commit-task, the checkpoint is deleted. On a crash, /np:resume-work reads the checkpoint to classify the session as resume, orphan, or clean.
RULES.md — project-wide always-follow
.nubos-pilot/RULES.md is the single, root-level file that captures rules valid on day 1 and day 1000, distinct from milestone-scoped M<NNN>-CONTEXT.md (phase-locked) and slice-scoped S<NNN>-PLAN.md. Sections: Always-Follow, Forbidden, Dependencies, Security, Logging, Code Style, Out-of-Scope (Forever).
Precedence: RULES.md > M<NNN>-CONTEXT.md > S<NNN>-PLAN.md > defaults. Every agent reads RULES.md before acting; np-security-reviewer cross-references it before flagging a finding (an explicit authorization there neutralizes a generic OWASP check). Rules promoted from M<NNN>-CONTEXT.md should reference the originating decision (D-XX from M<NNN>) for traceability.
Created by /np:new-project from templates/RULES.md; updated manually or via /np:add-todo --type rule … drafts that the next /np:discuss-phase reviews.
Knowledge index (ephemeral, gitignored)
.nubos-pilot/state/knowledge-index.json is a BM25-light full-text index over every Markdown file under .nubos-pilot/ — PROJECT.md, REQUIREMENTS.md, RULES.md, every milestone tree, codebase/, todos/, threads/, notes/. Built and queried via np-tools.cjs knowledge-index / knowledge-search / knowledge-stats; surfaced as /np:knowledge "<query>".
The file lives under the gitignored .nubos-pilot/state/ directory. It is a derived cache, not a source of truth; it is idempotently rebuilt from the indexed Markdown. np-planner, np-researcher, np-architect, np-build-fixer, and np-security-reviewer use it to find cross-milestone references and prior locked decisions without re-reading every artifact.
Session snapshot (ephemeral, gitignored)
.nubos-pilot/state/session-snapshot.json captures the live execution context at pause-time: current milestone + task, last 10 task commits, every still-open / read handoff, and the live checkpoint ids. Written by pause-work, read by resume-work to surface continuity context. The write is best-effort; a failure does not block pause-work, and the snapshot is a convenience layer on top of the authoritative STATE.md + checkpoints/ files.
Metrics
.nubos-pilot/metrics/*.jsonl is append-only. Every workflow can record events through np-tools.cjs metrics record. /np:stats aggregates them; /np:session-report summarizes since .last-session.
Gitignore guard
commit-task and commit route through lib/git.cjs.assertCommittablePaths(). The guard hard-fails when all declared paths are gitignored and warns when only some are. This stops the executor from silently producing empty commits.
Slice TODO rollup
slices/S<NNN>/TODO.md is a Markdown checkbox view of every task in the slice, generated from each task's frontmatter status:
| Task status | Checkbox |
|---|---|
pending | [ ] |
in-progress | [~] |
done | [x] |
skipped | [-] |
parked | [!] |
It is derived, not authoritative; task PLAN frontmatter stays the source of truth. Writers:
plan-milestone scaffold-all-tasksrenders one TODO.md per slice right after scaffolding.lib/tasks.cjs::setTaskStatus(called bycommit-task/skip/park/unpark) re-renders the affected slice's TODO.md on every status transition.- Explicit re-render:
node np-tools.cjs render-todo <slice-full-id>.
Counts (pending, in_progress, done, skipped, parked, total, updated_at) live in the TODO.md frontmatter, machine-readable and human-readable.
Agent handoffs
Agents exchange persistent, phase-independent notes via the handoff channel. This is where context that does not belong in commit messages or frontmatter lives: compromises the verifier must know about, plan flaws the next planner run should address, and cross-milestone traps.
Location:
- Milestone-scoped (default):
milestones/M<NNN>/handoffs/ - Project-global (no
--milestone): top-levelhandoffs/
Filename: <iso-8601>__<from>-to-<to>__<topic-slug>__<id>.md. Timestamps are monotone within a process so chronological sort is deterministic even under rapid writes.
Writer: np-tools.cjs handoff-write --from X --to Y --topic "..." [--milestone M<NNN>] [--slice M<NNN>-S<NNN>] [--task M<NNN>-S<NNN>-T<NNNN>] --body "..."
Readers: agents query via handoff-list --for <agent> [--status open], then handoff-read <id>, then acknowledge via handoff-status <id> acted.
Status lifecycle: open → read → acted → archived. Mutation rewrites only the status: line.
See the artifact schema for the exact frontmatter format and the agent catalog for per-agent write contracts.
Worktree isolation (opt-in)
Each slice can run in an isolated git worktree instead of on the user's active branch. This is controlled by workflow.worktree_isolation in config.json (default false). When disabled, all execution happens on the active branch and .nubos-pilot/worktrees/ stays empty.
Full mechanism, lifecycle, and invariants in ADR-0008.
Dashboard (read-only overview)
/np:dashboard (slash-command) → node .nubos-pilot/bin/np-tools.cjs dashboard produces a one-shot formatted view: every milestone, every slice in each milestone, and a checkbox row of every task's status per slice. It is read-only: no files written, no state mutated.
Output shape (no-color):
nubos-pilot
M001 — Auth Flow [active]
M001-S001 1 done · 1 in-progress · 1 pending
[x] [~] [ ]
M002 — Profile Page [planned]
no slices plannedFlags:
--json— emit the raw snapshot as JSON ({ milestones: [{ id, number, name, status, slices: [{ id, full_id, counts, task_statuses }] }] }). Useful for scripting.--no-color— plain text (no ANSI). Useful when piping or non-TTY.
By design, the dashboard has no --watch, no interactive drill-down, and no handoff/worktree/branch summary. It is a single-shot status view; deeper inspection composes existing commands: handoff-read <id>, render-todo <slice-full-id>, checkpoint show <task-full-id>, worktree-list. ADR-0009 documents why no interactive TUI was adopted.
