@ui8kit/uxdx 0.1.0

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 (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -0
  3. package/dist/uxdx.mjs +296 -0
  4. package/package.json +53 -0
  5. package/packages/sdlc/harness/README.md +58 -0
  6. package/packages/sdlc/harness/core/AGENTS.md +12 -0
  7. package/packages/sdlc/harness/core/README.md +15 -0
  8. package/packages/sdlc/harness/core/REVIEW.md +18 -0
  9. package/packages/sdlc/harness/core/changes/README.md +4 -0
  10. package/packages/sdlc/harness/core/cursor/rules/sdlc-core.mdc +15 -0
  11. package/packages/sdlc/harness/core/install.sh +3 -0
  12. package/packages/sdlc/harness/core/intent.md +25 -0
  13. package/packages/sdlc/harness/core/manifest.yaml +15 -0
  14. package/packages/sdlc/harness/core/plan.md +25 -0
  15. package/packages/sdlc/harness/core/sdlc.sh +230 -0
  16. package/packages/sdlc/harness/core/skills/sdlc-invariants/SKILL.md +20 -0
  17. package/packages/sdlc/harness/core/skills/sdlc-plan/SKILL.md +15 -0
  18. package/packages/sdlc/harness/core/spec.md +24 -0
  19. package/packages/sdlc/harness/core/start.sh +3 -0
  20. package/packages/sdlc/harness/full/AGENTS.md +15 -0
  21. package/packages/sdlc/harness/full/README.md +23 -0
  22. package/packages/sdlc/harness/full/REVIEW.md +19 -0
  23. package/packages/sdlc/harness/full/bands.yaml +13 -0
  24. package/packages/sdlc/harness/full/changes/README.md +4 -0
  25. package/packages/sdlc/harness/full/cursor/rules/sdlc-full.mdc +17 -0
  26. package/packages/sdlc/harness/full/evals/README.md +16 -0
  27. package/packages/sdlc/harness/full/hooks/README.md +17 -0
  28. package/packages/sdlc/harness/full/install.sh +3 -0
  29. package/packages/sdlc/harness/full/intent.md +26 -0
  30. package/packages/sdlc/harness/full/manifest.yaml +17 -0
  31. package/packages/sdlc/harness/full/plan.md +30 -0
  32. package/packages/sdlc/harness/full/sdlc.sh +230 -0
  33. package/packages/sdlc/harness/full/skills/sdlc-feedback/SKILL.md +18 -0
  34. package/packages/sdlc/harness/full/skills/sdlc-loop/SKILL.md +21 -0
  35. package/packages/sdlc/harness/full/skills/sdlc-review/SKILL.md +15 -0
  36. package/packages/sdlc/harness/full/spec.md +28 -0
  37. package/packages/sdlc/harness/full/start.sh +3 -0
  38. package/packages/sdlc/harness/light/AGENTS.md +13 -0
  39. package/packages/sdlc/harness/light/README.md +15 -0
  40. package/packages/sdlc/harness/light/changes/README.md +6 -0
  41. package/packages/sdlc/harness/light/cursor/rules/sdlc-light.mdc +16 -0
  42. package/packages/sdlc/harness/light/install.sh +3 -0
  43. package/packages/sdlc/harness/light/intent.md +24 -0
  44. package/packages/sdlc/harness/light/manifest.yaml +15 -0
  45. package/packages/sdlc/harness/light/plan.md +28 -0
  46. package/packages/sdlc/harness/light/sdlc.sh +230 -0
  47. package/packages/sdlc/harness/light/skills/sdlc-light/SKILL.md +30 -0
  48. package/packages/sdlc/harness/light/spec.md +23 -0
  49. package/packages/sdlc/harness/light/start.sh +3 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 ui8kit
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # UXDX
2
+
3
+ CLI to accumulate operator and developer experience packs. One binary, two
4
+ commands. Package name: [`@ui8kit/uxdx`](https://www.npmjs.com/package/@ui8kit/uxdx).
5
+
6
+ Homepage: [github.com/ui8kit/uxdx](https://github.com/ui8kit/uxdx)
7
+
8
+ ```text
9
+ npx @ui8kit/uxdx --help
10
+ npx @ui8kit/uxdx project | p | -p | --project [init] [--dir <path>] [--rules] [--force]
11
+ npx @ui8kit/uxdx sdlc | s | -s | --sdlc [init] [--dir <path>] --level light|core|full [--force] [--no-install]
12
+ ```
13
+
14
+ Same via Bun: `bunx @ui8kit/uxdx --help`.
15
+
16
+ The binary is still `uxdx`. After a local or global install you can call it
17
+ without the scope:
18
+
19
+ ```bash
20
+ npm i -g @ui8kit/uxdx
21
+ uxdx --help
22
+
23
+ npm i -D @ui8kit/uxdx
24
+ npx uxdx --help
25
+ ```
26
+
27
+ - `project` writes `README.md`, `.gitignore`, `.cursorignore`, and `.manual/`.
28
+ - `sdlc` copies a vendored harness pack into `.sdlc/`. `--level` is required.
29
+ - After copy, `sdlc` runs `.sdlc/sdlc.sh install` unless `--no-install`.
30
+
31
+ ## Local
32
+
33
+ ```bash
34
+ bun install
35
+ bun test
36
+ bun run uxdx -- --help
37
+ bun run build
38
+ ```
package/dist/uxdx.mjs ADDED
@@ -0,0 +1,296 @@
1
+ import { createRequire } from "node:module";
2
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
+
4
+ // packages/cli/src/parse.ts
5
+ var LEVELS = new Set(["light", "core", "full"]);
6
+ function takeFlag(rest, name) {
7
+ const i = rest.indexOf(name);
8
+ if (i === -1)
9
+ return false;
10
+ rest.splice(i, 1);
11
+ return true;
12
+ }
13
+ function takeOpt(rest, name) {
14
+ const i = rest.indexOf(name);
15
+ if (i === -1)
16
+ return null;
17
+ const v = rest[i + 1];
18
+ if (!v || v.startsWith("-")) {
19
+ throw new Error(`${name} requires a value`);
20
+ }
21
+ rest.splice(i, 2);
22
+ return v;
23
+ }
24
+ function stripInit(rest) {
25
+ if (rest[0] === "init")
26
+ rest.shift();
27
+ }
28
+ function parseArgv(argv) {
29
+ const args = argv.slice(2);
30
+ if (args.length === 0)
31
+ return { command: "help" };
32
+ const head = args[0];
33
+ const rest = args.slice(1);
34
+ if (head === "--help" || head === "-h") {
35
+ if (rest[0] === "-p" || rest[0] === "--project" || rest[0] === "p" || rest[0] === "project") {
36
+ return parseProject(rest.slice(1), true);
37
+ }
38
+ if (rest[0] === "-s" || rest[0] === "--sdlc" || rest[0] === "s" || rest[0] === "sdlc") {
39
+ return parseSdlc(rest.slice(1), true);
40
+ }
41
+ return { command: "help" };
42
+ }
43
+ if (head === "-p" || head === "--project" || head === "p" || head === "project") {
44
+ return parseProject(rest, false);
45
+ }
46
+ if (head === "-s" || head === "--sdlc" || head === "s" || head === "sdlc") {
47
+ return parseSdlc(rest, false);
48
+ }
49
+ throw new Error(`unknown command ${head} (try --help)`);
50
+ }
51
+ function parseProject(restIn, forcedHelp) {
52
+ const rest = [...restIn];
53
+ stripInit(rest);
54
+ const help = forcedHelp || takeFlag(rest, "--help") || takeFlag(rest, "-h");
55
+ const force = takeFlag(rest, "--force");
56
+ const rules = takeFlag(rest, "--rules");
57
+ const dir = takeOpt(rest, "--dir") ?? process.cwd();
58
+ if (rest.length)
59
+ throw new Error(`unexpected arguments: ${rest.join(" ")}`);
60
+ return { command: "project", help, dir, force, rules };
61
+ }
62
+ function parseSdlc(restIn, forcedHelp) {
63
+ const rest = [...restIn];
64
+ stripInit(rest);
65
+ const help = forcedHelp || takeFlag(rest, "--help") || takeFlag(rest, "-h");
66
+ const force = takeFlag(rest, "--force");
67
+ const noInstall = takeFlag(rest, "--no-install");
68
+ const dir = takeOpt(rest, "--dir") ?? process.cwd();
69
+ const levelRaw = takeOpt(rest, "--level");
70
+ let level = null;
71
+ if (levelRaw) {
72
+ if (!LEVELS.has(levelRaw))
73
+ throw new Error(`--level must be light, core, or full`);
74
+ level = levelRaw;
75
+ }
76
+ if (rest.length)
77
+ throw new Error(`unexpected arguments: ${rest.join(" ")}`);
78
+ return {
79
+ command: "sdlc",
80
+ help,
81
+ dir,
82
+ force,
83
+ level,
84
+ install: !noInstall
85
+ };
86
+ }
87
+ var ROOT_HELP = `uxdx — operator and developer experience packs
88
+
89
+ Usage:
90
+ uxdx [--help]
91
+ uxdx project | p | -p | --project [init] [--dir <path>] [--rules] [--force]
92
+ uxdx sdlc | s | -s | --sdlc [init] [--dir <path>] --level light|core|full [--force] [--no-install]
93
+
94
+ -p / --project Scaffold README, ignores, and .manual/
95
+ -s / --sdlc Install an SDLC harness pack into .sdlc/
96
+
97
+ Run uxdx project --help or uxdx sdlc --help for command flags.
98
+ `;
99
+ var PROJECT_HELP = `uxdx project — default operator layout
100
+
101
+ Aliases: project, p, -p, --project
102
+
103
+ [init] Default action (may be omitted)
104
+ --dir <path> Target directory (default: cwd)
105
+ --rules Create a stub .cursor/rules file
106
+ --force Overwrite files this command owns
107
+ --help This text
108
+ `;
109
+ var SDLC_HELP = `uxdx sdlc — install an SDLC harness into .sdlc/
110
+
111
+ Aliases: sdlc, s, -s, --sdlc
112
+
113
+ [init] Default action (may be omitted)
114
+ --level <name> Required: light | core | full
115
+ --dir <path> Target directory (default: cwd)
116
+ --no-install Copy the pack only; do not run .sdlc/sdlc.sh install
117
+ --force Replace an existing .sdlc of a different level
118
+ --help This text
119
+ `;
120
+
121
+ // packages/project/src/init.ts
122
+ import { mkdirSync, existsSync, readFileSync, writeFileSync } from "node:fs";
123
+ import { basename, join } from "node:path";
124
+ function ensureLine(file, line, _force) {
125
+ if (!existsSync(file)) {
126
+ writeFileSync(file, `${line}
127
+ `);
128
+ return;
129
+ }
130
+ const cur = readFileSync(file, "utf8");
131
+ if (cur.split(/\r?\n/).some((l) => l.trim() === line.trim()))
132
+ return;
133
+ const nl = cur.endsWith(`
134
+ `) || cur.length === 0 ? "" : `
135
+ `;
136
+ writeFileSync(file, `${cur}${nl}${line}
137
+ `);
138
+ }
139
+ function writeIfMissing(file, body, force) {
140
+ if (existsSync(file) && !force)
141
+ return;
142
+ writeFileSync(file, body);
143
+ }
144
+ function initProject(opts) {
145
+ const root = opts.dir;
146
+ mkdirSync(root, { recursive: true });
147
+ const done = [];
148
+ const name = basename(root);
149
+ const readme = join(root, "README.md");
150
+ writeIfMissing(readme, `# ${name}
151
+ `, opts.force);
152
+ done.push("README.md");
153
+ ensureLine(join(root, ".gitignore"), ".manual/", opts.force);
154
+ done.push(".gitignore");
155
+ ensureLine(join(root, ".cursorignore"), ".manual/", opts.force);
156
+ done.push(".cursorignore");
157
+ const projectDir = join(root, ".project");
158
+ mkdirSync(projectDir, { recursive: true });
159
+ writeIfMissing(join(projectDir, "README.md"), `# .project
160
+
161
+ Operator notes for this repository. See \`intent.md\` when present.
162
+ `, opts.force);
163
+ done.push(".project/");
164
+ mkdirSync(join(root, ".manual"), { recursive: true });
165
+ done.push(".manual/");
166
+ if (opts.rules) {
167
+ const rulesDir = join(root, ".cursor", "rules");
168
+ mkdirSync(rulesDir, { recursive: true });
169
+ writeIfMissing(join(rulesDir, "uxdx.mdc"), `---
170
+ description: UXDX operator layout
171
+ alwaysApply: true
172
+ ---
173
+
174
+ # UXDX
175
+
176
+ Read the repository operator notes before changing product scope.
177
+ `, opts.force);
178
+ done.push(".cursor/rules/");
179
+ }
180
+ return done;
181
+ }
182
+
183
+ // packages/sdlc/src/init.ts
184
+ import { cpSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync } from "node:fs";
185
+ import { dirname, join as join2 } from "node:path";
186
+ import { fileURLToPath } from "node:url";
187
+ import { spawnSync } from "node:child_process";
188
+ function harnessRoot() {
189
+ const here = dirname(fileURLToPath(import.meta.url));
190
+ const candidates = [
191
+ join2(here, "..", "harness"),
192
+ join2(here, "..", "..", "harness"),
193
+ join2(here, "..", "packages", "sdlc", "harness"),
194
+ join2(process.cwd(), "packages", "sdlc", "harness")
195
+ ];
196
+ for (const c of candidates) {
197
+ if (existsSync2(join2(c, "light", "manifest.yaml")))
198
+ return c;
199
+ }
200
+ throw new Error("uxdx: SDLC harness packs not found (packages/sdlc/harness)");
201
+ }
202
+ function readLevel(manifestPath) {
203
+ if (!existsSync2(manifestPath))
204
+ return null;
205
+ const m = readFileSync2(manifestPath, "utf8").match(/^level:\s*(\S+)/m);
206
+ return m ? m[1] : null;
207
+ }
208
+ function initSdlc(opts) {
209
+ const dest = join2(opts.dir, ".sdlc");
210
+ const existing = readLevel(join2(dest, "manifest.yaml"));
211
+ if (existing && existing !== opts.level && !opts.force) {
212
+ throw new Error(`uxdx: .sdlc already has level ${existing}; use --force to replace with ${opts.level}`);
213
+ }
214
+ const src = join2(harnessRoot(), opts.level);
215
+ if (!existsSync2(join2(src, "manifest.yaml"))) {
216
+ throw new Error(`uxdx: missing harness pack ${opts.level}`);
217
+ }
218
+ mkdirSync2(opts.dir, { recursive: true });
219
+ if (existsSync2(dest) && opts.force) {
220
+ rmSync(dest, { recursive: true, force: true });
221
+ }
222
+ mkdirSync2(dest, { recursive: true });
223
+ cpSync(src, dest, { recursive: true });
224
+ let installed = false;
225
+ if (opts.install) {
226
+ const script = join2(dest, "sdlc.sh");
227
+ const r = spawnSync("bash", [script, "install"], {
228
+ cwd: opts.dir,
229
+ encoding: "utf8"
230
+ });
231
+ if (r.error || r.status !== 0) {
232
+ const err = r.stderr || r.error?.message || `exit ${r.status}`;
233
+ throw new Error(`uxdx: .sdlc/sdlc.sh install failed (${err.trim()})`);
234
+ }
235
+ installed = true;
236
+ }
237
+ return { sdlcDir: dest, installed };
238
+ }
239
+
240
+ // packages/cli/src/main.ts
241
+ function run(argv) {
242
+ let parsed;
243
+ try {
244
+ parsed = parseArgv(argv);
245
+ } catch (e) {
246
+ console.error(`uxdx: ${e.message}`);
247
+ return 1;
248
+ }
249
+ if (parsed.command === "help") {
250
+ console.log(ROOT_HELP);
251
+ return 0;
252
+ }
253
+ if (parsed.command === "project") {
254
+ if (parsed.help) {
255
+ console.log(PROJECT_HELP);
256
+ return 0;
257
+ }
258
+ const done = initProject({
259
+ dir: parsed.dir,
260
+ force: parsed.force,
261
+ rules: parsed.rules
262
+ });
263
+ console.log(`uxdx: project init in ${parsed.dir}`);
264
+ for (const p of done)
265
+ console.log(` ${p}`);
266
+ return 0;
267
+ }
268
+ if (parsed.help) {
269
+ console.log(SDLC_HELP);
270
+ return 0;
271
+ }
272
+ if (!parsed.level) {
273
+ console.error("uxdx: --level is required (light | core | full)");
274
+ console.log(SDLC_HELP);
275
+ return 1;
276
+ }
277
+ try {
278
+ const { sdlcDir, installed } = initSdlc({
279
+ dir: parsed.dir,
280
+ level: parsed.level,
281
+ force: parsed.force,
282
+ install: parsed.install
283
+ });
284
+ console.log(`uxdx: sdlc ${parsed.level} → ${sdlcDir}${installed ? " (install ran)" : ""}`);
285
+ return 0;
286
+ } catch (e) {
287
+ console.error(e.message);
288
+ return 1;
289
+ }
290
+ }
291
+ if (__require.main == __require.module) {
292
+ process.exit(run(process.argv));
293
+ }
294
+ export {
295
+ run
296
+ };
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@ui8kit/uxdx",
3
+ "version": "0.1.0",
4
+ "description": "CLI to accumulate operator and developer experience packs",
5
+ "type": "module",
6
+ "bin": {
7
+ "uxdx": "./dist/uxdx.mjs"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/ui8kit/uxdx.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/ui8kit/uxdx/issues"
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "packages/sdlc/harness",
22
+ "README.md",
23
+ "LICENSE"
24
+ ],
25
+ "keywords": [
26
+ "cli",
27
+ "uxdx",
28
+ "sdlc",
29
+ "cursor",
30
+ "scaffold",
31
+ "ui8kit"
32
+ ],
33
+ "author": {
34
+ "name": "ui8kit",
35
+ "url": "https://github.com/ui8kit"
36
+ },
37
+ "license": "MIT",
38
+ "homepage": "https://github.com/ui8kit/uxdx",
39
+ "scripts": {
40
+ "build": "bun build packages/cli/src/main.ts --outfile dist/uxdx.mjs --target node",
41
+ "uxdx": "bun packages/cli/src/main.ts",
42
+ "test": "bun test",
43
+ "prepack": "bun run build",
44
+ "prepublishOnly": "bun test && bun run build",
45
+ "pack:check": "npm pack --dry-run"
46
+ },
47
+ "engines": {
48
+ "node": ">=20.0.0"
49
+ },
50
+ "workspaces": [
51
+ "packages/*"
52
+ ]
53
+ }
@@ -0,0 +1,58 @@
1
+ # SDLC harness packs (solo)
2
+
3
+ Copy-paste packs for the AI-native loop, sized for one operator. Source method:
4
+ [`.manual/sdlc-en`](../.manual/sdlc-en/README.md). Which product gets which pack:
5
+ [`.project/sdlc-scope.md`](../.project/sdlc-scope.md).
6
+
7
+ Later this tree can move to its own repo or a CLI (`sdlc init --level full`).
8
+ Until then the consumer copies **one** pack into **`.sdlc/`**.
9
+
10
+ ## How it works
11
+
12
+ ```
13
+ hinddy/brainstorm/.harness-sdlc/<level>/ (this gym)
14
+
15
+ │ copy (do not merge levels)
16
+
17
+ your-repo/.sdlc/ artifacts + overlay text
18
+
19
+ ├── intent.md spec.md plan.md templates at pack root
20
+ ├── changes/<slug>/ one folder per real change
21
+ ├── AGENTS.md overlay — merge into root AGENTS.md
22
+ ├── skills/ copy → .cursor/skills/
23
+ └── cursor/rules/ copy → .cursor/rules/
24
+ ```
25
+
26
+ 1. Pick **full**, **core**, or **light** from `sdlc-scope.md`. Never stack two packs.
27
+ 2. Copy the pack directory contents into `<repo>/.sdlc/` (keep `manifest.yaml`).
28
+ 3. **Activate Cursor** (rules/skills are not loaded from `.sdlc` by default):
29
+
30
+ ```bash
31
+ mkdir -p .cursor/rules .cursor/skills
32
+ cp .sdlc/cursor/rules/*.mdc .cursor/rules/
33
+ cp -R .sdlc/skills/* .cursor/skills/
34
+ ```
35
+
36
+ 4. **AGENTS.md**: if the repo already has a product `AGENTS.md` (SiteStarter, YPanel, …), **append** a short pointer. Do not replace stack-contract text. If there is no root file, copy `.sdlc/AGENTS.md` to the repo root.
37
+ 5. For each change: copy `intent.md` / `spec.md` / `plan.md` into `.sdlc/changes/<slug>/` and fill them. Leave the pack-root files as templates.
38
+ 6. Existing product rules (`.cursor/rules/stack-contract.mdc`, …) stay. The harness adds SDLC rules; it does not own Codex IA.
39
+
40
+ Human still merges. The agent writes artifacts and code; you accept `plan.md` before a large diff.
41
+
42
+ ## Levels
43
+
44
+ | Pack | Use when | Artifacts | Extra |
45
+ | --- | --- | --- | --- |
46
+ | `light/` | Product on an existing contract; small blast radius | `plan.md` required; `intent.md` optional; skip `spec.md` unless IA changes | No evals, no maintain bands |
47
+ | `core/` | Kernel, API, ARIA, shared library | `intent.md` + `plan.md`; compressed `spec.md` on boundary changes | Invariant skills; short `REVIEW.md` |
48
+ | `full/` | Portable Codex path, YPanel, anything that ships + is pinned | Full chain including `spec.md` | `REVIEW.md`, `evals/` stub, `bands.yaml` stub |
49
+
50
+ ## Future CLI (not built)
51
+
52
+ Suggested commands, matching `manifest.yaml` in each pack:
53
+
54
+ - `sdlc init --level full` → copy pack to `.sdlc`, overlay rules/skills, patch root `AGENTS.md` between markers
55
+ - `sdlc change start <slug>` → copy templates into `.sdlc/changes/<slug>/`
56
+ - `sdlc change accept` → remind to commit artifacts with the diff
57
+
58
+ Do not invent a second content REST or product kinds from this harness.
@@ -0,0 +1,12 @@
1
+ <!-- sdlc-harness:begin -->
2
+ ## SDLC harness (core)
3
+
4
+ This repo uses the **core** pack (`.harness-sdlc/core` → `.sdlc/`).
5
+
6
+ - Boundary, API, and policy changes: `intent.md` + short `spec.md` + `plan.md`.
7
+ - Mechanical fixes: `plan.md` only, still name the invariant you must not break.
8
+ - Skills: `sdlc-invariants`, `sdlc-plan`. Rule: `sdlc-core.mdc`.
9
+ - PR review against `.sdlc/REVIEW.md` (bugs, contract, compatibility).
10
+ - Do not add product behaviour to this module to ship a site. Consumers pin.
11
+ - Human merge. Skip eval-CI and maintain-bands unless this repo already runs them.
12
+ <!-- sdlc-harness:end -->
@@ -0,0 +1,15 @@
1
+ # Core harness
2
+
3
+ For kernels, shared libraries, and high blast-radius contracts.
4
+ Examples: FormSet, Framework, Panel, ui8kit/aria, Context.
5
+
6
+ Copy this directory to `<repo>/.sdlc/`. Overlay Cursor files — `../README.md`.
7
+
8
+ ## Per change
9
+
10
+ 1. Write `intent.md` when the change is a boundary, policy, or public API.
11
+ 2. Keep `spec.md` short: constraints + concerns, not a product PRD.
12
+ 3. `plan.md` always names files, order, tests, and what must not break.
13
+ 4. Encode repeated invariants as skills; do not repeat them in every plan.
14
+ 5. Human merge. No on-call agent. No eval suite unless this repo already has CI
15
+ for agent config (then add cases there, not a second framework).
@@ -0,0 +1,18 @@
1
+ # Review instructions (core)
2
+
3
+ ## Passes
4
+
5
+ Tag each finding with its pass:
6
+
7
+ - Bugs: logic errors, broken edge cases, subtle regressions
8
+ - Contract: public API, ARIA, kernel boundary, generated-file policy
9
+ - Compatibility: importers / pins still valid
10
+
11
+ ## Important vs nit
12
+
13
+ Important: would break callers, leak data, or violate the module contract.
14
+ Style and naming are nits. Cap nits at five; count the rest.
15
+
16
+ ## Do not report
17
+
18
+ Generated files the repo forbids editing, and anything CI already enforces.
@@ -0,0 +1,4 @@
1
+ # changes/
2
+
3
+ Copy `../intent.md`, `../spec.md`, and `../plan.md` into `./<slug>/` for a
4
+ boundary change. Mechanical work may keep `plan.md` only.
@@ -0,0 +1,15 @@
1
+ ---
2
+ description: Core SDLC — invariants, compressed spec, plan before large diffs
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Core SDLC overlay
7
+
8
+ This repository opted into `.sdlc` harness **core**.
9
+
10
+ - Artifacts: `.sdlc/changes/<slug>/`.
11
+ - Boundary changes need `intent.md`, a short `spec.md`, and `plan.md`.
12
+ - Review incoming diffs against `.sdlc/REVIEW.md`.
13
+ - Skills `sdlc-invariants` and `sdlc-plan` apply.
14
+ - Product `AGENTS.md` and stack-contract win on conflict.
15
+ - No autonomous production actions. No second content API.
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ exec "$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)/sdlc.sh" install "$@"
@@ -0,0 +1,25 @@
1
+ # Intent (core)
2
+
3
+ Author: <!-- name -->
4
+ Status: draft
5
+ Slug: <!-- kebab-case -->
6
+
7
+ ## Problem
8
+
9
+ What invariant, API, or shared behaviour is wrong or missing.
10
+
11
+ ## Proposed outcome
12
+
13
+ The new contract in one paragraph. Name the callers that must keep working.
14
+
15
+ ## Affected users and systems
16
+
17
+ Who imports this module. Do not expand into product IA of a consumer site.
18
+
19
+ ## Constraints
20
+
21
+ - Callers pin this module; do not require them to fork.
22
+ - No product schemas, carts, or site-specific kinds in a shared kernel.
23
+ - Existing tests that encode the compiler/API contract stay green.
24
+
25
+ ## Open questions
@@ -0,0 +1,15 @@
1
+ level: core
2
+ version: 1
3
+ copy_to: .sdlc
4
+ cursor:
5
+ rules: cursor/rules
6
+ skills: skills
7
+ agents_md:
8
+ overlay: AGENTS.md
9
+ merge_markers:
10
+ begin: "<!-- sdlc-harness:begin -->"
11
+ end: "<!-- sdlc-harness:end -->"
12
+ artifacts:
13
+ required: [plan.md]
14
+ on_boundary_change: [intent.md, spec.md]
15
+ review: REVIEW.md
@@ -0,0 +1,25 @@
1
+ # Plan (core)
2
+
3
+ From: `.sdlc/changes/<slug>/spec.md` (or intent if spec was skipped)
4
+ Status: draft
5
+
6
+ ## Files that change
7
+
8
+ -
9
+
10
+ ## Order of work
11
+
12
+ 1.
13
+ 2.
14
+
15
+ ## Proof
16
+
17
+ Commands that must pass (repo SoT: `AGENTS.md` / Makefile / `bun run`).
18
+
19
+ ## Risks
20
+
21
+ Blast radius for importers. Generated paths, frozen packages, public API.
22
+
23
+ ## Rollback
24
+
25
+ How to revert the pin in callers if this ships broken.