@novare-technologies/nvaid 0.2.0 → 0.2.2

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/README.md CHANGED
@@ -31,6 +31,27 @@ nvaid init --owning-repo frontend # preset the config's owning_repo
31
31
  nvaid init --yes # non-interactive (defaults to the AGENTS.md catch-all)
32
32
  ```
33
33
 
34
+ ## Upgrading
35
+
36
+ Upgrading is **two steps**, because `nvaid update` re-syncs a repo to the version of the
37
+ tool installed on your machine — it does not upgrade the tool itself:
38
+
39
+ ```bash
40
+ # 1. upgrade the tool (once per machine, when a new version ships)
41
+ npm i -g @novare-technologies/nvaid@latest
42
+
43
+ # 2. re-sync each repo to the new version (run inside each repo)
44
+ nvaid update
45
+ ```
46
+
47
+ nvaid checks npm (at most once a day, cached, non-blocking) and prints a one-line nudge
48
+ when a newer version is available — it never upgrades itself (the package manager owns the
49
+ tool's lifecycle). Silence the check with `NVAID_NO_UPDATE_CHECK=1`.
50
+
51
+ Note: `nvaid update` never touches hand-owned files (`config.yml`, `PROJECT-RULES.md`,
52
+ `DESIGN-CODE-DICTIONARY.md`, `intents/`). If a new version adds a config field, add it to
53
+ your `config.yml` by hand — the changelog will call these out.
54
+
34
55
  ## How it works
35
56
 
36
57
  - **Full skill set, no profiles.** `init` injects every skill into each selected agent. A
package/dist/cli.js CHANGED
@@ -13,6 +13,8 @@ var AGENTS = [
13
13
  id: "claude",
14
14
  label: "Claude Code",
15
15
  skillsPath: ".claude/skills",
16
+ commandsPath: ".claude/commands",
17
+ // /nvaid:install resolves from .claude/commands/nvaid/install.md
16
18
  instructionsFile: "CLAUDE.md",
17
19
  format: "markdown",
18
20
  bespoke: true
@@ -29,6 +31,8 @@ var AGENTS = [
29
31
  id: "cursor",
30
32
  label: "Cursor",
31
33
  skillsPath: ".cursor/rules",
34
+ commandsPath: ".cursor/commands",
35
+ // Cursor reads custom commands from .cursor/commands
32
36
  format: "mdc",
33
37
  bespoke: true
34
38
  },
@@ -109,8 +113,8 @@ var NVAID_DIR_NAME = "nvaid";
109
113
  var CONFIG_FILE = "config.yml";
110
114
  var AIDLC_ROOT_TOKEN = "{{AIDLC_ROOT}}";
111
115
  async function nvaidVersion() {
112
- const { readFile: readFile3 } = await import("fs/promises");
113
- const pkg = JSON.parse(await readFile3(resolve(TEMPLATES_DIR, "..", "package.json"), "utf8"));
116
+ const { readFile: readFile4 } = await import("fs/promises");
117
+ const pkg = JSON.parse(await readFile4(resolve(TEMPLATES_DIR, "..", "package.json"), "utf8"));
114
118
  return pkg.version;
115
119
  }
116
120
 
@@ -149,7 +153,10 @@ function skillTarget(projectRoot, agent, skill) {
149
153
  function commandTarget(projectRoot, agent, cmdFile) {
150
154
  const base = cmdFile.replace(/\.md$/, "");
151
155
  const ext = agent.format === "mdc" ? "mdc" : "md";
152
- return join(projectRoot, agent.skillsPath, `commands`, `nvaid-${base}.${ext}`);
156
+ if (agent.commandsPath) {
157
+ return join(projectRoot, agent.commandsPath, "nvaid", `${base}.${ext}`);
158
+ }
159
+ return join(projectRoot, agent.skillsPath, "nvaid-commands", `nvaid-${base}.${ext}`);
153
160
  }
154
161
  async function writeFileEnsuringDir(path, body, force, result) {
155
162
  if (!force && existsSync(path)) {
@@ -186,15 +193,14 @@ async function diffAgentFiles(opts) {
186
193
  for (const agent of opts.agents) {
187
194
  for (const skill of skills) {
188
195
  const src = join(SKILLS_SRC, skill, "SKILL.md");
189
- if (existsSync(src)) checks.push({ target: skillTarget(opts.projectRoot, agent, skill), src });
196
+ if (existsSync(src)) checks.push({ target: skillTarget(opts.projectRoot, agent, skill), src, agent });
190
197
  }
191
198
  for (const cmd of commands) {
192
- checks.push({ target: commandTarget(opts.projectRoot, agent, cmd), src: join(COMMANDS_SRC, cmd) });
199
+ checks.push({ target: commandTarget(opts.projectRoot, agent, cmd), src: join(COMMANDS_SRC, cmd), agent });
193
200
  }
194
201
  }
195
- for (const { target, src } of checks) {
196
- const agent = opts.agents.find((a) => target.includes(a.skillsPath.replace(/^\.\//, "")));
197
- const expected = await renderTemplate(src, agent ?? opts.agents[0]);
202
+ for (const { target, src, agent } of checks) {
203
+ const expected = await renderTemplate(src, agent);
198
204
  if (!existsSync(target)) {
199
205
  drift.push(`${relative(opts.projectRoot, target)} (missing)`);
200
206
  continue;
@@ -206,8 +212,7 @@ async function diffAgentFiles(opts) {
206
212
  }
207
213
  async function cleanAgentDirs(projectRoot, agents) {
208
214
  for (const agent of agents) {
209
- const dir = join(projectRoot, agent.skillsPath);
210
- const commandsDir = join(dir, "commands");
215
+ const commandsDir = agent.commandsPath ? join(projectRoot, agent.commandsPath, "nvaid") : join(projectRoot, agent.skillsPath, "nvaid-commands");
211
216
  if (existsSync(commandsDir)) await rm(commandsDir, { recursive: true, force: true });
212
217
  }
213
218
  }
@@ -460,6 +465,81 @@ async function runValidate() {
460
465
  return 0;
461
466
  }
462
467
 
468
+ // src/updateNotifier.ts
469
+ import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
470
+ import { homedir, tmpdir } from "os";
471
+ import { join as join4 } from "path";
472
+ import pc4 from "picocolors";
473
+ var PKG = "@novare-technologies/nvaid";
474
+ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
475
+ var FETCH_TIMEOUT_MS = 1500;
476
+ function cacheFile() {
477
+ const base = process.env.XDG_CACHE_HOME || join4(homedir(), ".cache");
478
+ return join4(base || tmpdir(), "nvaid", "update-check.json");
479
+ }
480
+ async function readCache() {
481
+ try {
482
+ return JSON.parse(await readFile3(cacheFile(), "utf8"));
483
+ } catch {
484
+ return null;
485
+ }
486
+ }
487
+ async function writeCache(c) {
488
+ try {
489
+ const f = cacheFile();
490
+ await mkdir3(join4(f, ".."), { recursive: true });
491
+ await writeFile3(f, JSON.stringify(c), "utf8");
492
+ } catch {
493
+ }
494
+ }
495
+ async function fetchLatest() {
496
+ try {
497
+ const ctrl = new AbortController();
498
+ const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
499
+ const res = await fetch(`https://registry.npmjs.org/${PKG}/latest`, {
500
+ signal: ctrl.signal
501
+ });
502
+ clearTimeout(timer);
503
+ if (!res.ok) return null;
504
+ const data = await res.json();
505
+ return data.version ?? null;
506
+ } catch {
507
+ return null;
508
+ }
509
+ }
510
+ function isNewer(a, b) {
511
+ const pa = a.split(".").map((n) => parseInt(n, 10));
512
+ const pb = b.split(".").map((n) => parseInt(n, 10));
513
+ for (let i = 0; i < 3; i++) {
514
+ const x = pa[i] ?? 0;
515
+ const y = pb[i] ?? 0;
516
+ if (x > y) return true;
517
+ if (x < y) return false;
518
+ }
519
+ return false;
520
+ }
521
+ async function notifyIfOutdated() {
522
+ if (process.env.NVAID_NO_UPDATE_CHECK) return;
523
+ const current = await nvaidVersion();
524
+ const cache = await readCache();
525
+ const now = Date.now();
526
+ let latest = null;
527
+ if (cache && now - cache.lastCheck < CHECK_INTERVAL_MS) {
528
+ latest = cache.latest;
529
+ } else {
530
+ latest = await fetchLatest();
531
+ if (latest) await writeCache({ lastCheck: now, latest });
532
+ }
533
+ if (!latest || !isNewer(latest, current)) return;
534
+ const line = (s) => process.stderr.write(s + "\n");
535
+ line("");
536
+ line(pc4.yellow(` \u250C\u2500 nvaid update available \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`));
537
+ line(pc4.yellow(" \u2502 ") + `${pc4.dim(current)} \u2192 ${pc4.green(latest)}`);
538
+ line(pc4.yellow(" \u2502 ") + `run: ${pc4.cyan(`npm i -g ${PKG}@latest`)}`);
539
+ line(pc4.yellow(" \u2502 ") + pc4.dim(`then re-sync your repo: nvaid update`));
540
+ line(pc4.yellow(` \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`));
541
+ }
542
+
463
543
  // src/cli.ts
464
544
  var program = new Command();
465
545
  program.name("nvaid").description("nvaid \u2014 install an AI-DLC skills + workflow toolkit into any coding agent").version(await nvaidVersion());
@@ -475,9 +555,13 @@ program.command("update").description("Re-sync agent files to the installed nvai
475
555
  await runUpdate();
476
556
  });
477
557
  program.command("validate").description("Fail if generated agent files are stale or hand-edited").action(async () => {
478
- process.exit(await runValidate());
558
+ const code = await runValidate();
559
+ await notifyIfOutdated();
560
+ process.exit(code);
479
561
  });
480
- program.parseAsync().catch((err) => {
562
+ program.parseAsync().then(async () => {
563
+ await notifyIfOutdated();
564
+ }).catch((err) => {
481
565
  console.error(err instanceof Error ? err.message : err);
482
566
  process.exit(1);
483
567
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@novare-technologies/nvaid",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "nvaid — one CLI that installs an AI-DLC skills-and-workflow toolkit into any coding agent, and houses intents, config, and the design-code dictionary in a single nvaid/ folder.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,7 @@
16
16
  "scripts": {
17
17
  "build": "tsup src/cli.ts --format esm --clean",
18
18
  "dev": "tsx src/cli.ts",
19
- "test": "vitest run --passWithNoTests",
19
+ "test": "vitest run",
20
20
  "typecheck": "tsc --noEmit",
21
21
  "prepublishOnly": "npm run build"
22
22
  },
@@ -47,13 +47,48 @@ not a file-scan's. This skill does that reading. A human reviews before it's mar
47
47
  narrative derived from reading the code; §1 references `config.yml`'s `tech_stack`
48
48
  rather than repeating it. Be honest in the "not yet mapped" section about coverage.
49
49
 
50
- 5. **Human review.** Present all three for review. Per propose-don't-dispose, you draft;
51
- a human confirms. Do not self-approve.
50
+ 5. **Set up ADRs (Architecture Decision Records) — the project's decision anchors.**
51
+ ADRs are where a significant decision is justified and preserved, so the project (and
52
+ any future agent) can trace *why* a choice was made and revisit it later. Create them
53
+ on demand, not as empty ceremony:
54
+ - If authoring PROJECT-RULES (step 3) surfaced genuine, non-obvious decisions — an
55
+ approved-stack choice, a deliberate constraint, something a reviewer might otherwise
56
+ question — **create `nvaid/adr/`** and seed one ADR per such decision, numbered
57
+ `ADR-001`, `ADR-002`, … using the template below. These are the decisions the project
58
+ has already made, now anchored.
59
+ - If the project is simple enough that no decision needs anchoring yet, **do not create
60
+ an empty `adr/` folder** — just tell the user ADRs will be added when the first real
61
+ decision arises (e.g. via the `solutions` skill flagging "needs a new ADR"). The
62
+ folder appears when there's a decision to put in it.
63
+ - Each ADR follows this shape:
64
+ ```markdown
65
+ ---
66
+ adr: ADR-NNN
67
+ title: "<the decision, stated as a choice>"
68
+ status: accepted # proposed | accepted | superseded by ADR-XXX
69
+ date: "<YYYY-MM-DD>"
70
+ ---
71
+ # ADR-NNN — <title>
72
+ ## Context
73
+ <the forces at play: what problem/constraint prompted this decision>
74
+ ## Decision
75
+ <what was decided, stated plainly>
76
+ ## Consequences
77
+ <what this makes easier, what it makes harder, what it rules out>
78
+ ## Alternatives considered
79
+ <options weighed and why they lost — so the decision can be revisited with the same context>
80
+ ```
81
+ - A decision anchored in an ADR must not contradict `PROJECT-RULES.md`; if it does,
82
+ reconcile them (an ADR can *drive* a rules change, recorded in the rules change log).
52
83
 
53
- 6. **Flip the gate.** Only after the user confirms each document is genuinely filled (not
84
+ 6. **Human review.** Present all documents (config, PROJECT-RULES, dictionary, any ADRs)
85
+ for review. Per propose-don't-dispose, you draft; a human confirms. Do not self-approve.
86
+
87
+ 7. **Flip the gate.** Only after the user confirms each document is genuinely filled (not
54
88
  placeholder text), set the matching flag in `config.yml`'s `install:` block to `true`:
55
89
  `config`, `project_rules`, `design_code_dictionary`. When all three are true, the
56
- workflow commands unblock.
90
+ workflow commands unblock. (ADRs are not a gate flag — they are created as decisions
91
+ warrant, not required for the install to be complete.)
57
92
 
58
93
  ## Boundaries
59
94
 
@@ -61,3 +96,5 @@ not a file-scan's. This skill does that reading. A human reviews before it's mar
61
96
  don't fabricate.
62
97
  - Never set an `install:` flag to `true` on a document that still contains template
63
98
  `<placeholder>` text or that the user hasn't confirmed.
99
+ - **Create `nvaid/adr/` only when there is a real decision to anchor** — never an empty
100
+ folder for its own sake.
@@ -84,4 +84,4 @@ context: ""
84
84
 
85
85
  # nvaid version this repo was last generated against. `nvaid validate` compares the
86
86
  # installed CLI version to this and flags drift.
87
- generated_with: "0.2.0"
87
+ generated_with: "0.2.2"
@@ -2,13 +2,13 @@
2
2
  name: customer-experience
3
3
  description: Drafts the Customer Experience Contract for an Intent, per customer-experience-contract-generation-rules.md. Use when asked to run the Customer Experience Skill or draft a Customer Experience contract during Mob Elaboration.
4
4
  invoked_by: Mob Elaboration (Ceremony 1), Phases 2–5
5
- output: file — intents/<INTENT-ID>/contracts/customer-experience-contract.md
5
+ output: file — nvaid/intents/<INTENT-ID>/contracts/customer-experience-contract.md
6
6
  ---
7
7
 
8
8
  # Customer Experience Skill
9
9
 
10
10
  Drafts the Customer Experience Contract for an Intent, per
11
- `docs/templates/customer-experience-contract-generation-rules.md` — reconciling what the
11
+ `{{AIDLC_ROOT}}/customer-experience-contract-generation-rules.md` — reconciling what the
12
12
  room actually committed to against what `intent.md` originally asked for.
13
13
 
14
14
  ## Steps
@@ -18,7 +18,7 @@ room actually committed to against what `intent.md` originally asked for.
18
18
  2. Write the Final Acceptance Criteria: the Intent's Success Criteria, incorporating
19
19
  what the other contracts actually committed to, not a verbatim restatement.
20
20
  3. Tie "done" to a concrete validation scenario, never just "the code merged."
21
- 4. Write `intents/<INTENT-ID>/contracts/customer-experience-contract.md`.
21
+ 4. Write `nvaid/intents/<INTENT-ID>/contracts/customer-experience-contract.md`.
22
22
 
23
23
  ## Boundaries
24
24
 
@@ -2,13 +2,13 @@
2
2
  name: frontend
3
3
  description: Drafts the Frontend Architecture Contract for an Intent, per frontend-architecture-contract-generation-rules.md. Use when asked to run the Frontend Skill or draft a Frontend contract during Mob Elaboration.
4
4
  invoked_by: Mob Elaboration (Ceremony 1), Phases 2–5
5
- output: file — intents/<INTENT-ID>/contracts/frontend-architecture-contract.md
5
+ output: file — nvaid/intents/<INTENT-ID>/contracts/frontend-architecture-contract.md
6
6
  ---
7
7
 
8
8
  # Frontend Skill
9
9
 
10
10
  Drafts the Frontend Architecture Contract for an Intent, per
11
- `docs/templates/frontend-architecture-contract-generation-rules.md` — consuming the
11
+ `{{AIDLC_ROOT}}/frontend-architecture-contract-generation-rules.md` — consuming the
12
12
  Backend contract's shapes verbatim rather than reinterpreting them.
13
13
 
14
14
  ## Steps
@@ -22,7 +22,7 @@ Backend contract's shapes verbatim rather than reinterpreting them.
22
22
  4. State Identity/Access implications explicitly, even when "none for this Intent" —
23
23
  never left implicit.
24
24
  5. List components touched (Design-Code Dictionary impact).
25
- 6. Write `intents/<INTENT-ID>/contracts/frontend-architecture-contract.md`.
25
+ 6. Write `nvaid/intents/<INTENT-ID>/contracts/frontend-architecture-contract.md`.
26
26
 
27
27
  ## Boundaries
28
28
 
@@ -7,13 +7,13 @@ output: link — a Jira or GitHub Projects ticket
7
7
 
8
8
  # Project Ticketing Skill
9
9
 
10
- Creates and updates Epics, Stories, and Bugs per `docs/templates/ISSUE-TRACKER-TEMPLATE.md`
10
+ Creates and updates Epics, Stories, and Bugs per `{{AIDLC_ROOT}}/ISSUE-TRACKER-TEMPLATE.md`
11
11
  — so ticket shape never drifts from one Intent to the next.
12
12
 
13
13
  ## Steps
14
14
 
15
15
  1. On Unit Breakdown (Mob Elaboration Phase 5), create one Story or Bug per Unit,
16
- classified per `docs/templates/unit-breakdown-rules.md` §3.
16
+ classified per `{{AIDLC_ROOT}}/unit-breakdown-rules.md` §3.
17
17
  2. Attach each ticket's Acceptance Criteria verbatim from the Unit's own design doc —
18
18
  never re-worded independently.
19
19
  3. As Mob Construction moves a Unit through Design → Building → Gates → Merged, update
@@ -2,13 +2,13 @@
2
2
  name: quality
3
3
  description: Drafts the Quality Architecture Contract for an Intent, per quality-architecture-contract-generation-rules.md. Use when asked to run the Quality Skill or draft a Quality contract during Mob Elaboration.
4
4
  invoked_by: Mob Elaboration (Ceremony 1), Phases 2–5
5
- output: file — intents/<INTENT-ID>/contracts/quality-architecture-contract.md
5
+ output: file — nvaid/intents/<INTENT-ID>/contracts/quality-architecture-contract.md
6
6
  ---
7
7
 
8
8
  # Quality Skill
9
9
 
10
10
  Drafts the Quality Architecture Contract for an Intent, per
11
- `docs/templates/quality-architecture-contract-generation-rules.md` — the Required Test
11
+ `{{AIDLC_ROOT}}/quality-architecture-contract-generation-rules.md` — the Required Test
12
12
  Coverage table the Unit Test and Integration Test gates run against.
13
13
 
14
14
  ## Steps
@@ -20,12 +20,12 @@ Coverage table the Unit Test and Integration Test gates run against.
20
20
  3. State which existing SRS NFRs this Intent's Units are held to, beyond the standing
21
21
  baseline; say "none beyond baseline" explicitly when true.
22
22
  4. Log any Known Gap the room consciously accepted, flagged rather than dropped.
23
- 5. Write `intents/<INTENT-ID>/contracts/quality-architecture-contract.md`.
23
+ 5. Write `nvaid/intents/<INTENT-ID>/contracts/quality-architecture-contract.md`.
24
24
 
25
25
  ## Boundaries
26
26
 
27
27
  - Never define Solution-Specific gates (Build, Code Coverage, Code Quality,
28
- Reusability, Regression Test, SAST) — those are fixed in `docs/templates/PROJECT-RULES.md`
28
+ Reusability, Regression Test, SAST) — those are fixed in `nvaid/PROJECT-RULES.md`
29
29
  §5.2, not something any Intent's contract opts into or out of.
30
30
  - A draft, not a verdict — flag it awaiting the Quality Architect's Sign-Off; never
31
31
  present it as final.
@@ -2,26 +2,28 @@
2
2
  name: solutions
3
3
  description: Drafts the Solutions Architecture Contract for an Intent, per solutions-architecture-contract-generation-rules.md. Use when asked to run the Solutions Skill or draft a Solutions contract during Mob Elaboration.
4
4
  invoked_by: Mob Elaboration (Ceremony 1), Phases 2–5
5
- output: file — intents/<INTENT-ID>/contracts/solutions-architecture-contract.md
5
+ output: file — nvaid/intents/<INTENT-ID>/contracts/solutions-architecture-contract.md
6
6
  ---
7
7
 
8
8
  # Solutions Skill
9
9
 
10
10
  Drafts the Solutions Architecture Contract for an Intent, per
11
- `docs/templates/solutions-architecture-contract-generation-rules.md` — the cross-role
11
+ `{{AIDLC_ROOT}}/solutions-architecture-contract-generation-rules.md` — the cross-role
12
12
  boundary and consistency check every other contract this session has to fit inside.
13
13
 
14
14
  ## Steps
15
15
 
16
- 1. Assess whether this Intent introduces a new system container, crosses an SRS System
17
- Container boundary, or needs a new ADR — state the answer even when it's "no" on
18
- every count.
16
+ 1. Assess whether this Intent introduces a new system container, crosses an architectural
17
+ boundary, or **needs a new ADR** — state the answer even when it's "no" on every count.
18
+ If a new ADR is warranted, record it as `nvaid/adr/ADR-NNN-<slug>.md` (next free number)
19
+ using the ADR shape from the `/nvaid:install` skill: Context, Decision, Consequences,
20
+ Alternatives considered. An ADR is a decision anchor — it must not contradict
21
+ `nvaid/PROJECT-RULES.md`; if it would, reconcile them.
19
22
  2. State explicitly what this Intent is and isn't allowed to touch.
20
- 3. Flag any unsupervised-action surface `docs/templates/PROJECT-RULES.md` §7 doesn't
21
- already cover.
23
+ 3. Flag any unsupervised-action surface `nvaid/PROJECT-RULES.md` §7 doesn't already cover.
22
24
  4. Cross-check the other contracts drafted this session for contradictions — the
23
25
  Consistency Gate, recorded in writing.
24
- 5. Write `intents/<INTENT-ID>/contracts/solutions-architecture-contract.md`.
26
+ 5. Write `nvaid/intents/<INTENT-ID>/contracts/solutions-architecture-contract.md`.
25
27
 
26
28
  ## Boundaries
27
29
 
@@ -2,7 +2,7 @@
2
2
  name: unit-breakdown
3
3
  description: Cuts an Intent into Units of Work, each with its own Acceptance Criteria, per unit-breakdown-rules.md. Use when asked to run the Unit Breakdown Skill, break down an Intent into Units, or produce a Unit Breakdown during Mob Elaboration Phase 5.
4
4
  invoked_by: Mob Elaboration (Ceremony 1), Phase 5
5
- output: file — intents/<INTENT-ID>/unit-breakdown.md
5
+ output: file — nvaid/intents/<INTENT-ID>/unit-breakdown.md
6
6
  ---
7
7
 
8
8
  # Unit Breakdown Skill
@@ -12,14 +12,14 @@ a first-cut proposal the room then critiques, not the decomposition of record.
12
12
 
13
13
  ## Steps
14
14
 
15
- 1. Read the Intent file (`intents/<INTENT-ID>/intent.md`) and its stated success
15
+ 1. Read the Intent file (`nvaid/intents/<INTENT-ID>/intent.md`) and its stated success
16
16
  criteria.
17
17
  2. Propose a decomposition into Units, each with its own Acceptance Criteria narrowed
18
- from the Intent's success criteria, per `docs/templates/unit-breakdown-rules.md` §2.
18
+ from the Intent's success criteria, per `{{AIDLC_ROOT}}/unit-breakdown-rules.md` §2.
19
19
  3. Classify each Unit as a Story or Bug (§3), and size it per the file's decomposition
20
20
  heuristics (§4).
21
21
  4. Number Units per §5.
22
- 5. Write `intents/<INTENT-ID>/unit-breakdown.md` — the contract index every
22
+ 5. Write `nvaid/intents/<INTENT-ID>/unit-breakdown.md` — the contract index every
23
23
  Architecture Contract Skill downstream reads from.
24
24
 
25
25
  ## Boundaries
@@ -27,5 +27,5 @@ a first-cut proposal the room then critiques, not the decomposition of record.
27
27
  - This is a proposal, not the decomposition of record. Mob Elaboration Phase 3
28
28
  ("Mark it up alone") and Phase 4 ("Negotiate live") are where the room actually owns
29
29
  the cut — flag this file as a draft awaiting that review, never as final.
30
- - Read `docs/templates/unit-breakdown-rules.md` in full before drafting; don't rely on
30
+ - Read `{{AIDLC_ROOT}}/unit-breakdown-rules.md` in full before drafting; don't rely on
31
31
  this summary alone for the numbering and classification rules.