Skip to content

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

FileSource of truthDerived
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.mdscaffolded 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 with id/depends_on/wave/tier attributes.
  • T<NNNN>-PLAN.md — read by lib/tasks.cjs.loadTaskGraph and the executor. Must have valid frontmatter per TASK_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_EXCL writes to a <file>.lock sidecar, atomic on every supported filesystem.
  • Embeds pid, hostname, and acquiredAt in 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 statusCheckbox
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-tasks renders one TODO.md per slice right after scaffolding.
  • lib/tasks.cjs::setTaskStatus (called by commit-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-level handoffs/

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 planned

Flags:

  • --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.