@nusoft/nuos-build-catalogue 0.9.0 → 0.10.1

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 (90) hide show
  1. package/dist/cli.d.ts +13 -0
  2. package/dist/cli.js +472 -0
  3. package/dist/commands/create.d.ts +70 -0
  4. package/dist/commands/create.js +341 -0
  5. package/dist/commands/format.d.ts +19 -0
  6. package/dist/commands/format.js +89 -0
  7. package/dist/commands/handlers.d.ts +35 -0
  8. package/dist/commands/handlers.js +132 -0
  9. package/dist/commands/init.d.ts +41 -0
  10. package/dist/commands/init.js +289 -0
  11. package/dist/commands/prompt.d.ts +44 -0
  12. package/dist/commands/prompt.js +100 -0
  13. package/dist/commands/write.d.ts +39 -0
  14. package/dist/commands/write.js +247 -0
  15. package/dist/embedder/ollama.d.ts +54 -0
  16. package/dist/embedder/ollama.js +164 -0
  17. package/dist/embedder/openai.d.ts +21 -0
  18. package/dist/embedder/openai.js +56 -0
  19. package/dist/embedder/select.d.ts +9 -0
  20. package/dist/embedder/select.js +27 -0
  21. package/dist/embedder/stub.d.ts +15 -0
  22. package/dist/embedder/stub.js +40 -0
  23. package/dist/embedder/types.d.ts +21 -0
  24. package/dist/embedder/types.js +6 -0
  25. package/dist/embedder/vertex.d.ts +41 -0
  26. package/dist/embedder/vertex.js +94 -0
  27. package/dist/indexer/chunk.d.ts +20 -0
  28. package/dist/indexer/chunk.js +196 -0
  29. package/dist/indexer/crawl.d.ts +20 -0
  30. package/dist/indexer/crawl.js +66 -0
  31. package/dist/indexer/metadata.d.ts +21 -0
  32. package/dist/indexer/metadata.js +126 -0
  33. package/dist/indexer/upsert.d.ts +26 -0
  34. package/dist/indexer/upsert.js +152 -0
  35. package/dist/migrate/parsers.d.ts +17 -0
  36. package/dist/migrate/parsers.js +123 -0
  37. package/dist/migrate/run.d.ts +22 -0
  38. package/dist/migrate/run.js +142 -0
  39. package/dist/migrate/store.d.ts +20 -0
  40. package/dist/migrate/store.js +52 -0
  41. package/dist/migrate/types.d.ts +57 -0
  42. package/dist/migrate/types.js +13 -0
  43. package/dist/regenerate/check.d.ts +11 -0
  44. package/dist/regenerate/check.js +97 -0
  45. package/dist/regenerate/diff.d.ts +18 -0
  46. package/dist/regenerate/diff.js +38 -0
  47. package/dist/regenerate/types.d.ts +52 -0
  48. package/dist/regenerate/types.js +14 -0
  49. package/dist/runtime/ac-parse.d.ts +63 -0
  50. package/dist/runtime/ac-parse.js +196 -0
  51. package/dist/runtime/markdown-edit.d.ts +53 -0
  52. package/dist/runtime/markdown-edit.js +101 -0
  53. package/dist/runtime/markdown-render.d.ts +27 -0
  54. package/dist/runtime/markdown-render.js +209 -0
  55. package/dist/runtime/mis-adapter.d.ts +35 -0
  56. package/dist/runtime/mis-adapter.js +364 -0
  57. package/dist/runtime/runtime.d.ts +20 -0
  58. package/dist/runtime/runtime.js +39 -0
  59. package/dist/search/format.d.ts +6 -0
  60. package/dist/search/format.js +23 -0
  61. package/dist/search/query.d.ts +29 -0
  62. package/dist/search/query.js +71 -0
  63. package/dist/store/open.d.ts +14 -0
  64. package/dist/store/open.js +16 -0
  65. package/package.json +5 -3
  66. package/templates/protocols/end-of-session.md +19 -0
  67. package/templates/protocols/persona-new.md +43 -0
  68. package/templates/protocols/start-of-session.md +19 -0
  69. package/templates/protocols/wu-new.md +52 -0
  70. package/templates/starter-kit/CLAUDE.md +73 -0
  71. package/templates/starter-kit/README.md +116 -0
  72. package/templates/starter-kit/docs/build/END-OF-SESSION.md +62 -0
  73. package/templates/starter-kit/docs/build/START-OF-SESSION.md +33 -0
  74. package/templates/starter-kit/docs/build/STATE.md +47 -0
  75. package/templates/starter-kit/docs/build/decisions/D001-template.md +38 -0
  76. package/templates/starter-kit/docs/build/decisions/_index.md +30 -0
  77. package/templates/starter-kit/docs/build/maps/01-template.md +126 -0
  78. package/templates/starter-kit/docs/build/maps/_index.md +63 -0
  79. package/templates/starter-kit/docs/build/open-questions/_index.md +26 -0
  80. package/templates/starter-kit/docs/build/personas/001-template.md +68 -0
  81. package/templates/starter-kit/docs/build/personas/_index.md +77 -0
  82. package/templates/starter-kit/docs/build/risks/_index.md +28 -0
  83. package/templates/starter-kit/docs/build/sessions/0000-00-00-template.md +47 -0
  84. package/templates/starter-kit/docs/build/sessions/_index.md +27 -0
  85. package/templates/starter-kit/docs/build/work-units/001-template.md +82 -0
  86. package/templates/starter-kit/docs/build/work-units/_index.md +34 -0
  87. package/templates/starter-kit/docs/contracts/_index.md +26 -0
  88. package/templates/starter-kit/docs/guides/_index.md +26 -0
  89. package/templates/starter-kit/docs/philosophy/_index.md +26 -0
  90. package/templates/starter-kit/methodfile.json +54 -0
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Output formatter — human-readable table or JSON.
3
+ */
4
+ export function formatHumanReadable(hits) {
5
+ if (hits.length === 0)
6
+ return '(no results)';
7
+ return hits
8
+ .map((h, i) => {
9
+ const idTag = h.idInKind ? ` ${h.idInKind}` : '';
10
+ const status = h.status ? ` [${h.status}]` : '';
11
+ const heading = h.headings ? ` › ${h.headings}` : '';
12
+ const lines = h.startLine ? `:${h.startLine}-${h.endLine}` : '';
13
+ return [
14
+ `${(i + 1).toString().padStart(2)}. ${h.path}${lines}`,
15
+ ` ${h.fileKind}${idTag}${status}${heading} (score ${h.score.toFixed(4)})`,
16
+ ` ${h.snippet}`,
17
+ ].join('\n');
18
+ })
19
+ .join('\n\n');
20
+ }
21
+ export function formatJson(hits) {
22
+ return JSON.stringify({ hits }, null, 2);
23
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Search — embed the query, call NuVector.searchKnowledge, format results.
3
+ */
4
+ import type { NuVector } from '@nusoft/nuvector';
5
+ import type { Embedder } from '../embedder/types.js';
6
+ export interface SearchOptions {
7
+ query: string;
8
+ limit?: number;
9
+ kind?: string;
10
+ status?: string;
11
+ }
12
+ export interface SearchHit {
13
+ chunkId: string;
14
+ path: string;
15
+ fileKind: string;
16
+ idInKind: string;
17
+ status: string;
18
+ date: string;
19
+ headings: string;
20
+ startLine: number;
21
+ endLine: number;
22
+ score: number;
23
+ snippet: string;
24
+ }
25
+ export declare function runSearch(store: NuVector, embedder: Embedder, options: SearchOptions): Promise<{
26
+ hits: SearchHit[];
27
+ embedMs: number;
28
+ searchMs: number;
29
+ }>;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Search — embed the query, call NuVector.searchKnowledge, format results.
3
+ */
4
+ import { TENANT } from '../store/open.js';
5
+ export async function runSearch(store, embedder, options) {
6
+ const limit = options.limit ?? 10;
7
+ const t1 = Date.now();
8
+ const [queryEmbedding] = await embedder.embed([options.query]);
9
+ const embedMs = Date.now() - t1;
10
+ const t2 = Date.now();
11
+ // Use retrieveContext (not searchKnowledge — that's the NuWiki four-layer
12
+ // entry point and only returns Layer 1 article summaries). For arbitrary
13
+ // document chunks like the catalogue indexer's, retrieveContext + kind
14
+ // filter is the correct method.
15
+ const result = await store.retrieveContext({
16
+ embedding: queryEmbedding,
17
+ tenant: TENANT,
18
+ topK: Math.max(limit * 3, 30),
19
+ filters: { kind: 'document_chunk' },
20
+ });
21
+ const searchMs = Date.now() - t2;
22
+ const items = (result?.items ?? []);
23
+ let hits = items.map((it) => {
24
+ const meta = it.metadata ?? {};
25
+ return {
26
+ chunkId: String(it.ref ?? ''),
27
+ path: String(meta.path ?? ''),
28
+ fileKind: String(meta.file_kind ?? ''),
29
+ idInKind: String(meta.id_in_kind ?? ''),
30
+ status: String(meta.status ?? ''),
31
+ date: String(meta.date ?? ''),
32
+ headings: String(meta.headings ?? ''),
33
+ startLine: Number(meta.start_line ?? 0),
34
+ endLine: Number(meta.end_line ?? 0),
35
+ score: Number(it.score ?? 0),
36
+ snippet: makeSnippet(String(it.text ?? it.summary ?? ''), options.query),
37
+ };
38
+ });
39
+ if (options.kind) {
40
+ hits = hits.filter((h) => h.fileKind === options.kind);
41
+ }
42
+ if (options.status) {
43
+ hits = hits.filter((h) => h.status.toLowerCase().includes(options.status.toLowerCase()));
44
+ }
45
+ return { hits: hits.slice(0, limit), embedMs, searchMs };
46
+ }
47
+ function makeSnippet(text, query) {
48
+ const flat = text.replace(/\s+/g, ' ').trim();
49
+ if (flat.length <= 200)
50
+ return flat;
51
+ const tokens = query
52
+ .toLowerCase()
53
+ .split(/\s+/u)
54
+ .filter((t) => t.length > 2);
55
+ let bestIdx = -1;
56
+ for (const tok of tokens) {
57
+ const idx = flat.toLowerCase().indexOf(tok);
58
+ if (idx >= 0) {
59
+ bestIdx = idx;
60
+ break;
61
+ }
62
+ }
63
+ if (bestIdx === -1) {
64
+ return flat.slice(0, 200) + '…';
65
+ }
66
+ const start = Math.max(0, bestIdx - 60);
67
+ const end = Math.min(flat.length, bestIdx + 140);
68
+ const prefix = start > 0 ? '…' : '';
69
+ const suffix = end < flat.length ? '…' : '';
70
+ return prefix + flat.slice(start, end) + suffix;
71
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * NuVector store factory — opens the file-backed store at the configured
3
+ * location, creating it if missing. The verification gate (scripts/
4
+ * verify-persistence.ts) confirmed file-backed persistence works in
5
+ * @nusoft/nuvector@0.1.0; see WU 110 notes for the verdict and known
6
+ * API quirks.
7
+ */
8
+ import { NuVector } from '@nusoft/nuvector';
9
+ export declare const TENANT = "nuos_build_catalogue";
10
+ export interface StoreConfig {
11
+ storagePath: string;
12
+ dimensions: number;
13
+ }
14
+ export declare function openStore(config: StoreConfig): Promise<NuVector>;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * NuVector store factory — opens the file-backed store at the configured
3
+ * location, creating it if missing. The verification gate (scripts/
4
+ * verify-persistence.ts) confirmed file-backed persistence works in
5
+ * @nusoft/nuvector@0.1.0; see WU 110 notes for the verdict and known
6
+ * API quirks.
7
+ */
8
+ import { NuVector } from '@nusoft/nuvector';
9
+ export const TENANT = 'nuos_build_catalogue';
10
+ export async function openStore(config) {
11
+ return NuVector.open({
12
+ storage: config.storagePath,
13
+ dimensions: config.dimensions,
14
+ tenant: TENANT,
15
+ });
16
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nusoft/nuos-build-catalogue",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
4
4
  "description": "NuOS build-catalogue tooling: semantic search (WU 110) + migration runner that lifts markdown artefacts into JSON-backed workflow records (WU 111, Phase G).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,15 +9,17 @@
9
9
  "files": [
10
10
  "dist",
11
11
  "scripts",
12
+ "templates",
12
13
  "README.md"
13
14
  ],
14
15
  "publishConfig": {
15
16
  "access": "restricted"
16
17
  },
17
18
  "scripts": {
18
- "build": "tsc",
19
+ "build": "rm -rf dist && tsc && chmod +x dist/cli.js",
20
+ "prepublishOnly": "npm run build",
19
21
  "verify-storage": "tsx scripts/verify-persistence.ts",
20
- "test": "tsx --test tests/chunk.test.ts tests/metadata.test.ts tests/crawl.test.ts tests/migrate.test.ts tests/commands-read.test.ts tests/regenerate.test.ts tests/commands-write.test.ts tests/ac-parse.test.ts tests/create.test.ts",
22
+ "test": "tsx --test tests/chunk.test.ts tests/metadata.test.ts tests/crawl.test.ts tests/migrate.test.ts tests/commands-read.test.ts tests/regenerate.test.ts tests/commands-write.test.ts tests/ac-parse.test.ts tests/create.test.ts tests/init.test.ts",
21
23
  "typecheck": "tsc --noEmit",
22
24
  "index": "tsx src/cli.ts index",
23
25
  "search": "tsx src/cli.ts search"
@@ -0,0 +1,19 @@
1
+ # end-of-session
2
+
3
+ Run the end-of-session protocol for this NuOS Build Method project.
4
+
5
+ Follow `docs/build/END-OF-SESSION.md` exactly. Nine steps:
6
+
7
+ 1. **Update the active work unit's notes section** with what was attempted, what worked, what did not work and why, what was learned, and what the next concrete action should be. Apply the auditor's-question test: could a third-party reader read this entry and answer "why was this done and what justifies the next step?" without contacting the team?
8
+ 2. **Capture any new decisions** as `docs/build/decisions/D<NNN>-<slug>.md` files plus an entry in `decisions/_index.md`.
9
+ 3. **Capture any new open questions** as `docs/build/open-questions/Q<NNN>-<slug>.md` files plus an entry in `open-questions/_index.md`. If a question was both raised AND resolved this session, capture it as a decision instead.
10
+ 4. **Capture any new risks** as entries in `docs/build/risks/_index.md`.
11
+ 5. **Update the work-units index.** Confirm status icons reflect reality. **When a WU promotes to ✅, move its file from `work-units/<NNN>-<slug>.md` to `work-units/done/<NNN>-<slug>.md` and update the row link in `_index.md` to point at `done/<file>`.** Fix internal relative paths in the moved file (one level deeper after the move).
12
+ 6. **Update `STATE.md`.** Refresh: last-updated date, last-session reference, active work unit, "What was just done", "What is next" if priorities shifted, decisions/questions/risks tables.
13
+ 7. **Write a session log entry** in `docs/build/sessions/<YYYY-MM-DD>-<slug>.md`. Add a row to `sessions/_index.md`.
14
+ 8. **Verify nothing is lost.** Every decision has a file + index entry. Every question has a file + index entry. Every risk has an index entry. STATE.md reflects current state. Cross-references resolve. Dates are right.
15
+ 9. **Commit.** A single commit with the message `end-of-session: <YYYY-MM-DD> — <one-line summary>`. The pre-commit hook (per WU 128) will validate index integrity on the way through; if it blocks, fix the underlying drift, do not bypass with `--no-verify`.
16
+
17
+ **End-of-session is non-negotiable.** Without it, work is lost — that is the single rule the catalogue is built on.
18
+
19
+ If you cannot run the full protocol (rushing to stop, handing off mid-task), at minimum write one paragraph into the active WU's notes section: *"session ended without full end-of-session protocol; the state is approximately X; outstanding actions Y."* Then run the full protocol at the start of the next session before any new work.
@@ -0,0 +1,43 @@
1
+ # persona-new
2
+
3
+ Create a new persona (P-NNN) for this NuOS Build Method project.
4
+
5
+ A persona is a **specification of who will use an outcome and what situation they will be in when they use it** — not a demographic snapshot, but a design constraint. Personas live as first-class catalogue entries (per D046) so they can be cited by stable handle from multiple WUs.
6
+
7
+ If arguments are provided (`$ARGUMENTS` for OpenCode/Claude Code, prompt-supplied for Codex), use them as the persona name; otherwise prompt the operator for the name.
8
+
9
+ Steps:
10
+
11
+ 1. **Determine the next available P number.** Scan `docs/build/personas/` and `docs/build/personas/done/` for the maximum P-NNN prefix. The new number is max + 1.
12
+ 2. **Slugify the persona name** — lowercase, dashes for spaces, no special characters, max 60 chars.
13
+ 3. **Generate the file** at `docs/build/personas/P<NNN>-<slug>.md` from the template at `starter-kit/docs/build/personas/001-template.md`. Replace placeholders with operator-supplied values.
14
+ 4. **Prompt the operator for the seven dimensions:**
15
+
16
+ - **1. Identity** — who they are in the context of *this system*. Not their age or job title in the abstract — their relationship to this particular system. What account do they have? What role do they play? What other systems have they used that shape their expectations?
17
+ - **2. Reality** — physical environment when they use the outcome. Device, connection quality, noise level, time pressure. Real conditions, not idealised ones.
18
+ - **3. Psychology** — technical confidence, stress level, tolerance for confusion. Will they read instructions or click around? Will they abandon if a page takes more than three seconds?
19
+ - **4. Trigger** — what brings them to this outcome. A real-world event, not a UI click. The event in their life that created the need.
20
+ - **5. History** — what they have done before arriving at this outcome. Returning user vs first-time visitor. Saved details vs no context.
21
+ - **6. Success** — what "done" looks like from *their* perspective. Not what the system logs — what they *feel*. This drives the design.
22
+ - **7. Constraints** — what they cannot or will not do. Defines the outer boundary of acceptable design.
23
+
24
+ 5. **Prompt for the acid-test refinement.** The hardest legitimate user — this persona with the most demanding combination of real constraints. Not a hostile user; a legitimate one with the worst realistic conditions. Slow device, low technical confidence, time pressure, complex situation. Design for the acid-test and the standard cases hold.
25
+ 6. **Prompt for paired persona (if any).** If this persona's outcomes are paired with another's — a customer who books an event and an organiser who receives the booking — capture the paired P-NNN. If no pair exists yet, the operator may file the paired persona next via a second `persona-new` invocation.
26
+ 7. **Apply the persona discipline checks:**
27
+
28
+ - **Does this persona change a design decision?** If you could substitute this persona with a different one and the WU specification would be identical, the persona is decorative. Surface the gap and prompt for refinement.
29
+ - **Does this persona have specific triggers, not just a demographic profile?** A persona without triggers is a character in search of a plot. Surface and prompt for refinement.
30
+ - **Is the acid-test the hardest legitimate combination, or only a slightly harder version of the easy case?** The acid-test must be uncomfortable to design for — that is its point.
31
+
32
+ 8. **Add a row to `docs/build/personas/_index.md`.** Status `🟢 active`. The "Used by WUs" cell stays empty until WUs cite it (which the `wu-new` protocol will update).
33
+ 9. **Surface to the operator:**
34
+ - The new persona file path (clickable)
35
+ - The row added to `_index.md`
36
+ - Any discipline checks that surfaced gaps (paired-persona suggestion; "this persona doesn't yet constrain a decision" warning)
37
+ - The next concrete action — typically: file a WU that serves this persona (`wu-new`), or file the paired persona
38
+
39
+ **Discipline:** the persona is a design constraint or it is decoration. The seven dimensions exist to make every design decision answerable. If the persona file does not constrain at least one decision a future WU will need to make, rewrite it until it does.
40
+
41
+ **On the multi-month context (per D046):** in serious systems, personas are referenced from many WUs over many months. The seven-dimension shape is what makes the persona reusable — generic personas ("the user") force every WU to invent the persona inline; specific personas with stable handles let outcomes inherit the constraint. The persona register is the catalogue's commitment to this reuse.
42
+
43
+ If the operator wants to skip a dimension because it feels obvious, accommodate but record what was skipped — a future WU may need exactly that dimension and find it missing. The catalogue's value is that what was decided is recorded; what was not yet decided is also recorded, as a known gap.
@@ -0,0 +1,19 @@
1
+ # start-of-session
2
+
3
+ Run the start-of-session protocol for this NuOS Build Method project.
4
+
5
+ Follow `docs/build/START-OF-SESSION.md` exactly. Five steps:
6
+
7
+ 1. **Read `docs/build/STATE.md` in full.** It is the single source of "where are we right now?"
8
+ 2. **Read the most recent session log entry** in `docs/build/sessions/` (the file with the most recent date in its filename). Read it in full.
9
+ 3. **Read the active work unit** named in STATE.md, in full — including the notes / log section at the bottom.
10
+ 4. **Skim `docs/build/open-questions/_index.md` and `docs/build/risks/_index.md`** for any items that block the active work unit. If any are blocking, surface them now before any work starts.
11
+ 5. **Surface to the operator:**
12
+ - Where the project is right now (one sentence)
13
+ - The active work unit and its current status (one sentence)
14
+ - Any blockers (one bullet each)
15
+ - The next concrete action (one bullet)
16
+
17
+ **Wait for confirmation before proceeding to substantive work.** If the operator wants to do something other than the proposed next action, that is fine — but record the divergence either as a new work unit or as a note on the active work unit.
18
+
19
+ If STATE.md looks out of date — or if there is no active work unit named — note that to the operator immediately. Likely the previous end-of-session was skipped.
@@ -0,0 +1,52 @@
1
+ # wu-new
2
+
3
+ Create a new work unit (WU) for this NuOS Build Method project.
4
+
5
+ If arguments are provided (`$ARGUMENTS` for OpenCode/Claude Code, prompt-supplied for Codex), use them as the WU title; otherwise prompt the operator for the title.
6
+
7
+ The WU template carries the **six-field outcome shape** (per D046): persona link, trigger, walkthrough with failure paths, verification (= acceptance criteria), contracts produced, contracts consumed. For infrastructure WUs (build, publish, hardening, refactors) the persona/trigger/walkthrough fields are marked `N/A — infrastructure WU` and the rest is unchanged.
8
+
9
+ Steps:
10
+
11
+ 1. **Determine the next available WU number.** Scan `docs/build/work-units/` and `docs/build/work-units/done/` for the maximum 3-digit prefix. The new number is max + 1.
12
+ 2. **Slugify the title** — lowercase, dashes for spaces, no special characters, max 60 chars.
13
+ 3. **Ask the operator: is this an outcome WU (a user-facing capability) or an infrastructure WU (build, publish, hardening, refactor)?** If outcome, walk the full six-field flow. If infrastructure, skip persona/trigger/walkthrough and ask for the technical artefacts directly.
14
+ 4. **Generate the file** at `docs/build/work-units/<NNN>-<slug>.md` from the template at `starter-kit/docs/build/work-units/001-template.md`. Replace placeholders with operator-supplied values.
15
+ 5. **Prompt the operator (outcome WU) for:**
16
+ - **Persona** — which P-NNN persona does this outcome serve? If none exists yet, prompt to run `persona-new` first. For paired outcomes (a customer-side outcome paired with an organiser-side one), capture both persona links.
17
+ - **Trigger** — the real-world event that makes this outcome necessary. Not a UI click; the event in the persona's life that created the need.
18
+ - **Outcome** — one paragraph. Apply the single-sentence test: *"What will be true when this is done that is not true now?"* That sentence is the outcome.
19
+ - **Walkthrough** — numbered steps from the persona's perspective. For each step, surface the **five failure-path injection points**: (1) what if the persona cannot complete this step in one sitting? (2) what if the information is incorrect or missing? (3) what if the system itself fails? (4) what if the persona makes a mistake? (5) what if they realise immediately afterwards they used the wrong information? Failure handling lives inline at each step, not as a separate section.
20
+ - **Acceptance criteria (= verification)** — 5 to 10 criteria, each phrased as an inspection that passes or fails. Apply the auditor's-question test: *"Can a third-party reader confirm 'yes, this is shipped' by inspection alone?"* Each criterion must be evaluable by a person looking at the running system, not inferred from technical state.
21
+ - **Contracts produced** — what this WU makes available to other WUs once it lands, in domain language. Not "a row in the bookings table"; "a confirmed booking record, linked to a specific customer and a specific event".
22
+ - **Contracts consumed** — what must already exist before this WU can run. Each entry should map to another WU's `Contracts produced` field. If something this WU consumes is not produced by any WU in the plan, surface that gap immediately — file it as an open question or a new WU before this one starts.
23
+ - **Dependencies** — existing WU numbers this depends on (drawn from the contracts-consumed mapping; blank if none).
24
+ - **Decision implemented** — D-NNN if any (blank for none).
25
+ - **Forward-compatibility commitments** — if this WU's shape decisions affect later WUs, name them (per Pattern C).
26
+ 6. **Prompt the operator (infrastructure WU) for:**
27
+ - **Outcome** — single-sentence test as above.
28
+ - **Acceptance criteria** — same discipline.
29
+ - **Dependencies, decision implemented, forward-compatibility commitments** — same as outcome WU.
30
+ - **Persona / Trigger / Walkthrough** — auto-filled with `N/A — infrastructure WU.`
31
+ - **Contracts produced** — list the technical artefacts (e.g., "`@nusoft/nuwiki@0.1.4` published privately on npm").
32
+ - **Contracts consumed** — list the WUs whose output this WU builds on.
33
+ 7. **Apply the four quality traps** to the outcome before saving (operator review, not enforced by tooling today):
34
+ - **Vagueness:** could this outcome be implemented in more than one way that satisfies its wording but produces different user experiences?
35
+ - **Technical language:** does any part describe implementation rather than behaviour?
36
+ - **Happy path only:** does the walkthrough describe only what happens when everything goes right?
37
+ - **Kitchen sink:** does this WU try to do more than one thing? Could it be split into two outcomes with separate triggers and separate verification?
38
+
39
+ Surface any traps that fired and offer to rewrite the affected section before saving.
40
+ 8. **Add a row to `docs/build/work-units/_index.md`** in the appropriate phase section, with status `🟢 ready` (or `🔵 proposed` if dependencies aren't met).
41
+ 9. **If the WU cites a P-NNN, update that persona's `Used by WUs` list** to include the new WU.
42
+ 10. **Surface to the operator:**
43
+ - The new WU file path (clickable)
44
+ - The row added to `_index.md`
45
+ - Any inferred dependencies that should be confirmed
46
+ - Any quality traps that fired and were addressed (or deferred to a later refinement)
47
+
48
+ **Discipline:** every acceptance criterion must be checkable by inspection, not described as a feature. *"The login page works"* is not an acceptance criterion. *"When a user submits a valid form, a row appears in `users` and an audit entry in `audit_events`"* is.
49
+
50
+ **On the six-field shape (per D046):** the planning depth is what makes the catalogue durable. Skipping persona/trigger/walkthrough for an outcome WU produces a feature wearing an outcome-shaped name. Skipping contracts produced/consumed produces an outcome that integrates with nothing. The fields are not bureaucracy; each one closes a category of silent assumption the LLM teammate would otherwise fill in invisibly.
51
+
52
+ If the operator pushes back on the auto-numbered slug or wants to adjust acceptance criteria, accommodate. The catalogue's strength is that the operator is in charge of the substance; the protocol just makes sure the substance is recorded properly.
@@ -0,0 +1,73 @@
1
+ # {{PROJECT_NAME}} — Project Bootstrap for an LLM Teammate
2
+
3
+ > This file is read at the start of every session. It is the entry point to the project memory.
4
+
5
+ ## What this project is
6
+
7
+ {{PROJECT_NAME}} is {{PROJECT_TAGLINE}}.
8
+
9
+ This project runs **the NuOS Build Method** — see [the canonical strategic note](https://github.com/DarrenJCoxon/nuos/blob/main/docs/THE-NUOS-BUILD-METHOD.md) for the discipline, and [the harness contract](https://github.com/DarrenJCoxon/nuos/blob/main/docs/contracts/method-harness.md) for how the catalogue plugs into NuOS when wired.
10
+
11
+ ## At the start of every session — always
12
+
13
+ Run the start-of-session protocol. The single command is:
14
+
15
+ > "Run start-of-session"
16
+
17
+ When asked to do this, follow [docs/build/START-OF-SESSION.md](docs/build/START-OF-SESSION.md) exactly. It will:
18
+
19
+ 1. Read [docs/build/STATE.md](docs/build/STATE.md) — the always-current project snapshot
20
+ 2. Read the most recent entry in [docs/build/sessions/](docs/build/sessions/)
21
+ 3. Identify the active work unit and read it in full
22
+ 4. Surface any blocking open questions or risks
23
+ 5. Confirm the state and propose the next concrete action
24
+
25
+ ## At the end of every session — always
26
+
27
+ Run the end-of-session protocol. The single command is:
28
+
29
+ > "Run end-of-session"
30
+
31
+ When asked to do this, follow [docs/build/END-OF-SESSION.md](docs/build/END-OF-SESSION.md) exactly. It will:
32
+
33
+ 1. Update the active work unit's notes with what was done
34
+ 2. Update [docs/build/STATE.md](docs/build/STATE.md) to reflect current state
35
+ 3. Write a new session log entry in [docs/build/sessions/](docs/build/sessions/)
36
+ 4. Update any decisions, open questions, or risks that emerged
37
+ 5. Update the relevant `_index.md` files
38
+ 6. Verify nothing is lost
39
+
40
+ If a session ends without the end-of-session protocol being run, work may be lost. Always run it.
41
+
42
+ ## The canonical operational plan lives in maps
43
+
44
+ The `docs/build/maps/` directory holds the canonical operational plan for this project. **Story-level detail lives in maps**, not in fragmented planning docs. Each phase step in a map has an acceptance criterion and a verification gate (a specific file/grep/test in the target repo that proves the step is done).
45
+
46
+ When a session starts, after reading STATE.md, identify the active map and read the active phase step. The verification gate names exactly what to run to know whether the step is complete. **Run the gate before doing more work.**
47
+
48
+ If you find yourself writing *"likely"*, *"presumably"*, *"should be"* in code or planning text, **stop**. The hedge word indicates a verification step was skipped. Run the gate, replace the hedge with the result, then continue.
49
+
50
+ **Before generating non-trivial implementation, produce at least two fundamentally different designs, evaluate each, then pick.** This is Ousterhout's "design it twice" applied to agent-led work. Agents satisfice on the first plausible idea; the structured comparison is what catches blind spots before they reach code. Record the alternatives in the WU's notes (or a D-NNN decision file).
51
+
52
+ These are two of the five agentic-age patterns codified in [`THE-NUOS-BUILD-METHOD.md`](https://github.com/DarrenJCoxon/nuos/blob/main/docs/THE-NUOS-BUILD-METHOD.md) §post-Phase-3 epistemic discipline. The discipline isn't borrowed from agile; it's shaped for the specific failure modes of LLM-driven building.
53
+
54
+ ## The single rule
55
+
56
+ > Every non-trivial action taken in the build must leave a durable trace in the catalogue.
57
+
58
+ This is enforced by mechanism, not memory. The end-of-session protocol is the mechanism. Run it.
59
+
60
+ ## What never to do
61
+
62
+ - Never make architectural decisions without recording them in [docs/build/decisions/](docs/build/decisions/)
63
+ - Never start work outside the active work unit without recording why
64
+ - Never proceed past a `🔴 blocked` work unit without first resolving its blocker
65
+ - Never assume something is decided because it "must have been"; if the catalogue does not record it, surface it as a new open question
66
+
67
+ ## Where implementation work happens
68
+
69
+ [Edit this section to describe where this project's code lives. If implementation is in-repo, say so. If it lives in sibling repos, list them and explain the relationship to this catalogue.]
70
+
71
+ ## The current state, at a glance
72
+
73
+ The project state changes as work proceeds. The always-current snapshot is at [docs/build/STATE.md](docs/build/STATE.md). Read it.
@@ -0,0 +1,116 @@
1
+ # NuOS Catalogue Starter
2
+
3
+ > A copy-this-and-go template for any project adopting **the NuOS Build Method**. Unzip into a fresh project, replace the `{{PROJECT_NAME}}` placeholders, commit, and the project is harness-ready. The starter kit gets you to a healthy catalogue in under thirty minutes; from there, the build pack `build-pack-nuos-method` (when it ships per WU 049) can wire up the NuOS runtime harness.
4
+
5
+ ## What this is
6
+
7
+ The NuOS Build Method is described in [`nuos/docs/THE-NUOS-BUILD-METHOD.md`](https://github.com/DarrenJCoxon/nuos/blob/main/docs/THE-NUOS-BUILD-METHOD.md). The method requires a structured catalogue: decisions, work units, sessions, risks, open questions, plus protocols for starting and ending every session.
8
+
9
+ This starter kit is the **catalogue scaffold** — the directory tree, the template files, the `methodfile.json` manifest, and the protocols pre-populated with sensible defaults. It is the static, copy-and-edit form of a NuOS-method catalogue.
10
+
11
+ The starter kit is *not* the harness. The harness is when NuVector indexes the catalogue, NuFlow runs the protocols, and NuWiki compiles the snapshots. Until you wire the harness, the catalogue runs on operator discipline and an LLM teammate. That is sufficient for a small team running the method on its own; harnessing comes when scale demands it.
12
+
13
+ ## What's in here
14
+
15
+ ```
16
+ .
17
+ ├── README.md # this file
18
+ ├── methodfile.json # the manifest the harness reads
19
+ ├── CLAUDE.md # session-start instruction for an LLM teammate
20
+ └── docs/
21
+ ├── philosophy/ # the project's architectural commitments — narrative
22
+ │ └── _index.md
23
+ ├── contracts/ # type-stable surfaces — what each part of the project promises
24
+ │ └── _index.md
25
+ ├── guides/ # the persuasion layer — investor, customer, partner-readable
26
+ │ └── _index.md
27
+ └── build/
28
+ ├── STATE.md # always-current snapshot — read this first every session
29
+ ├── START-OF-SESSION.md # the protocol — every session starts by following this
30
+ ├── END-OF-SESSION.md # the protocol — every session ends by following this
31
+ ├── maps/ # the canonical operational plan(s) — story-level detail with verification gates
32
+ │ ├── _index.md
33
+ │ └── 01-template.md
34
+ ├── decisions/
35
+ │ ├── _index.md
36
+ │ └── D001-template.md
37
+ ├── work-units/
38
+ │ ├── _index.md
39
+ │ └── 001-template.md
40
+ ├── sessions/
41
+ │ ├── _index.md
42
+ │ └── 0000-00-00-template.md
43
+ ├── risks/
44
+ │ └── _index.md
45
+ └── open-questions/
46
+ └── _index.md
47
+ ```
48
+
49
+ ## Epistemic discipline — the central commitment for agent-led building
50
+
51
+ Method note (post-Phase-3 evolution; see [`THE-NUOS-BUILD-METHOD.md`](https://github.com/DarrenJCoxon/nuos/blob/main/docs/THE-NUOS-BUILD-METHOD.md)). The catalogue's discipline isn't borrowed from agile — it's shaped for the specific failure modes of LLM-driven building. The five load-bearing patterns:
52
+
53
+ 1. **Verification gates anchored in target-repo files** (in maps; per phase step) — exact targets so the agent can't generate plausible-looking work that misses reality
54
+ 2. **Maps as single canonical plan** — single entry point so the agent (or fresh session) can't act on partial context
55
+ 3. **Contracts as immutable truth** — fixed reference points that turn agent reasoning into citation rather than improvisation
56
+ 4. **Hedge words as stop signal** — "likely", "presumably", "should be" indicate a verification step was skipped; replace with the grep/test/file-read result before the work ships
57
+ 5. **Design alternatives before implementation** — Ousterhout's "design it twice"; for any non-trivial architectural choice, produce at least two fundamentally different designs, evaluate, then pick (or hybrid) before generating implementation. Agents satisfice on the first plausible idea; structured comparison catches blind spots before they reach code
58
+
59
+ These appear throughout the catalogue. The maps directory is where (1), (2), and (5) are concretely enforced. Pattern (3) is enforced by `docs/contracts/`. Pattern (4) is enforced by the operator's discipline + memory rules.
60
+
61
+ ## How to adopt — the thirty-minute path
62
+
63
+ 1. **Copy the tree** into your project's repo. Either paste these files directly into a fresh project root, or use this directory as a git template.
64
+
65
+ 2. **Replace the placeholders.** Search-and-replace across the tree:
66
+ - `{{PROJECT_NAME}}` — your project's name (e.g., "Acme")
67
+ - `{{PROJECT_TAGLINE}}` — one-sentence description
68
+ - `{{PROJECT_DOMAIN}}` — the domain you're working in (e.g., "education", "healthcare")
69
+ - `{{PROJECT_ROLE}}` — `consumer` if you're building on top of NuOS; `standalone` if you're using the method without the trifecta
70
+ - `{{TODAY}}` — today's date in `YYYY-MM-DD` format
71
+
72
+ 3. **Commit the catalogue.** Single first commit. Use the message:
73
+ ```
74
+ Adopt the NuOS Build Method — catalogue scaffold in place
75
+ ```
76
+
77
+ 4. **Write your first decision.** Open `docs/build/decisions/D001-template.md`, rename it to match your first real architectural commitment (e.g., `D001-we-are-building-on-postgres.md`), fill it in. Update `docs/build/decisions/_index.md`.
78
+
79
+ 5. **Write your first work unit.** Open `docs/build/work-units/001-template.md`, rename it (e.g., `001-postgres-schema-bootstrap.md`), fill it in. Update `docs/build/work-units/_index.md`.
80
+
81
+ 6. **Update STATE.md.** Replace the placeholder content with your project's actual current state (Phase 0, no work units shipped, first decision in flight).
82
+
83
+ 7. **Run the start-of-session protocol.** Tell your LLM teammate: *"Run start-of-session"*. It should read STATE.md, the most recent session log, and the active work unit. (At first start, there is no session log — the protocol notes that and prompts for the first one.)
84
+
85
+ 8. **Do work, then run end-of-session.** When you stop, tell your LLM teammate: *"Run end-of-session"*. It will write a session log entry, update STATE.md, update the work-unit notes, and update the relevant `_index.md` files.
86
+
87
+ That is the loop. Every session opens with start-of-session. Every session closes with end-of-session. The catalogue accumulates. Nothing is lost.
88
+
89
+ ## What you do not need to do
90
+
91
+ - **Do not write a `philosophy/` document on day one.** The philosophy emerges as you commit decisions. By decision 10, patterns are clear; that is when the philosophy doc becomes worth writing.
92
+ - **Do not write `contracts/` documents on day one.** Contracts are how stable surfaces communicate. Until you have stable surfaces, you have no contracts to write.
93
+ - **Do not write guides on day one.** Guides are the persuasion layer; you write them when you need to persuade somebody (an investor, a customer, a regulator). Until then, they're empty `_index.md` files.
94
+
95
+ The catalogue's strength is that it grows as you need it. Day one is just the scaffold and the first decision and the first work unit. That is enough.
96
+
97
+ ## When to wire the harness
98
+
99
+ When the catalogue gets big enough that grep starts being slow, when manual maintenance of STATE.md drifts, when the project starts producing confidential material that needs role-aware redaction — that is the moment to wire the NuOS runtime harness. The thresholds are roughly:
100
+
101
+ - **NuVector** when the catalogue has more than 50 entries (decisions + WUs + session logs combined)
102
+ - **NuFlow** when the protocols are being run more than once a day (multiple operators or multiple sessions per day)
103
+ - **NuWiki** when STATE.md is being hand-edited and is drifting from reality
104
+ - **The deidentifier subsystem** from day one if your domain is regulated (clinical, legal, statutory)
105
+
106
+ The build pack `build-pack-nuos-method` (per WU 049 in the NuOS catalogue) automates the wiring when it ships. Until then, the markdown-only catalogue is fully functional — the method works without the harness; the harness just makes it scale.
107
+
108
+ ## License
109
+
110
+ [choose a license — MIT or Apache-2.0 are typical]
111
+
112
+ ## Pointers
113
+
114
+ - [The NuOS Build Method — durable strategic note](https://github.com/DarrenJCoxon/nuos/blob/main/docs/THE-NUOS-BUILD-METHOD.md) — what this kit operationalises
115
+ - [The Method Harness contract](https://github.com/DarrenJCoxon/nuos/blob/main/docs/contracts/method-harness.md) — how the catalogue plugs into NuOS
116
+ - [NuOS itself](https://github.com/DarrenJCoxon/nuos) — the worked example; every claim the method makes is demonstrated by NuOS's own catalogue
@@ -0,0 +1,62 @@
1
+ # End-of-Session Protocol
2
+
3
+ > Run this every time a session ends. The point is to commit the session's results into the catalogue before context is lost. **If a session ends without this protocol, work is lost.** This is the single load-bearing ritual that prevents the project from drifting.
4
+
5
+ ## Steps
6
+
7
+ 1. **Update the active work unit's notes section.** Append a dated entry describing:
8
+ - What was attempted
9
+ - What worked
10
+ - What did not work and why
11
+ - What was learned (if any pattern is starting to emerge)
12
+ - What the next concrete action should be
13
+
14
+ The auditor's-question test: *"Could a third-party auditor read this entry and answer 'why was this done and what evidence justifies the next step?' without contacting the team?"* If yes, the entry is sufficient.
15
+
16
+ 2. **Update [`STATE.md`](STATE.md)** to reflect the session's outcome:
17
+ - Refresh "What is currently in flight"
18
+ - Refresh "What just shipped" if anything completed
19
+ - Refresh "What is next"
20
+ - Update the work-units-in-flight table
21
+ - Update the decisions-made-recently table if any decisions landed
22
+ - Update the "Last updated" date
23
+
24
+ 3. **Write a new session log entry** in [`sessions/`](sessions/) named `YYYY-MM-DD-short-description.md`. The entry should include:
25
+ - **What this session was about** — one paragraph framing
26
+ - **What was done** — chronological narrative; reference any commits
27
+ - **Decisions that surfaced** — link to D-NNN files
28
+ - **Open questions raised** — link to Q-NNN files
29
+ - **Risks identified** — link to R-NNN files
30
+ - **What's next** — the concrete next action (mirrors STATE.md "What is next")
31
+
32
+ 4. **Update the relevant `_index.md` files**:
33
+ - If a new D-NNN landed, add it to `decisions/_index.md`
34
+ - If a new WU landed or a WU's status changed, update `work-units/_index.md`
35
+ - Always add the new session log entry to `sessions/_index.md`
36
+ - If a new Q-NNN or R-NNN landed, update those indexes
37
+
38
+ 5. **Verify nothing is lost.** Read the session log entry back and check:
39
+ - Did anything happen that is not captured somewhere?
40
+ - Are there cross-references that should exist? (a WU should link to the decision that justifies it; a session should link to the WU it advanced)
41
+ - Are the dates right?
42
+
43
+ 6. **Commit.** Single commit, message format:
44
+ ```
45
+ end-of-session: {{TODAY}} — [one-line summary of session outcome]
46
+ ```
47
+
48
+ ## What this protocol guarantees
49
+
50
+ - No work happens that is not recorded in the catalogue
51
+ - Every session has a replay-grade trace; a fresh session (or a fresh operator) can pick up exactly where this one left off
52
+ - The catalogue compounds rather than drifts
53
+
54
+ ## What to do if a session was unusually short or unusually long
55
+
56
+ - **Short session (<30 min, no work landed):** Still write a session entry. It can be brief: "explored X, decided not to start; reason: Y." This counts as a non-trivial action because it consumed a decision-making slot.
57
+ - **Long session (multiple WUs touched, multiple decisions):** Write one session entry covering all of it. If the session is genuinely two sessions worth of work that happened in one sitting, write two entries with appropriate timestamps.
58
+
59
+ ## What to do if you cannot run the full protocol
60
+
61
+ - **You're rushing to stop:** at minimum, write one paragraph into the active WU's notes section saying *"session ended without full end-of-session protocol; the state is approximately X; outstanding actions Y."* Then run the full protocol at the start of the next session before any new work.
62
+ - **You're handing off mid-task to another operator:** do run the full protocol, even if the work is incomplete. The next operator needs the current truth.
@@ -0,0 +1,33 @@
1
+ # Start-of-Session Protocol
2
+
3
+ > Run this every time a session begins. The point is to absorb the project state in under sixty seconds and propose a concrete next action. If this takes more than two minutes to follow, the catalogue is unhealthy — fix that first.
4
+
5
+ ## Steps
6
+
7
+ 1. **Read [`STATE.md`](STATE.md)** in full. It is the single source of "where are we right now?"
8
+
9
+ 2. **Read the most recent session log entry** in [`sessions/`](sessions/). The directory is sorted newest-last; the most recent entry is the last one chronologically. If there is no session log yet, this is the first session — note that and proceed.
10
+
11
+ 3. **Read the active work unit** named in STATE.md. Read it in full, including the notes / log section at the bottom. The notes capture what the previous session learned that has not yet been generalised into a decision.
12
+
13
+ 4. **Skim `open-questions/_index.md` and `risks/_index.md`** for any items that block the active work unit. If any are blocking, surface them now before any work starts.
14
+
15
+ 5. **Surface to the operator:**
16
+ - Where the project is right now (one sentence)
17
+ - What the active work unit is and what its current status is (one sentence)
18
+ - Any blockers (one bullet each)
19
+ - The next concrete action (one bullet)
20
+
21
+ 6. **Confirm the next action with the operator before starting work.** If the operator wants to do something other than the proposed next action, that is fine — but record the divergence either as a new work unit or as a note on the active work unit.
22
+
23
+ ## What this protocol guarantees
24
+
25
+ - No session begins without a clear understanding of where the project stands
26
+ - No work happens outside an acknowledged work unit (or with an explicit acknowledgement of why it is outside)
27
+ - Blockers are surfaced before work starts, not after work has been wasted on something that cannot ship
28
+
29
+ ## What to do if something is missing
30
+
31
+ - **STATE.md is out of date.** Note this to the operator immediately. Likely the previous end-of-session was skipped or incomplete. Check the latest session log and the latest WU notes for what the truth actually is.
32
+ - **No active work unit named.** Note this. Likely a phase boundary just closed and the next WU has not been picked yet. Surface the candidate WUs and ask the operator to pick.
33
+ - **Blocking open questions.** Stop. Surface them. Do not start work that depends on an unresolved question.