@adobe/data-ai 0.9.83 → 0.9.84

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 (59) hide show
  1. package/.claude/rules/README.md +42 -0
  2. package/.claude/rules/archetypes.md +60 -0
  3. package/.claude/rules/cohesion.md +66 -0
  4. package/.claude/rules/data-modelling.md +71 -0
  5. package/.claude/rules/element.md +130 -0
  6. package/.claude/rules/features/data/index.md +35 -0
  7. package/.claude/rules/features/data/state.md +54 -0
  8. package/.claude/rules/features/ecs/actions.md +32 -0
  9. package/.claude/rules/features/ecs/archetypes.md +46 -0
  10. package/.claude/rules/features/ecs/components.md +41 -0
  11. package/.claude/rules/features/ecs/computed.md +26 -0
  12. package/.claude/rules/features/ecs/conformance.md +69 -0
  13. package/.claude/rules/features/ecs/index.md +179 -0
  14. package/.claude/rules/features/ecs/indexes.md +63 -0
  15. package/.claude/rules/features/ecs/resources.md +28 -0
  16. package/.claude/rules/features/ecs/services.md +24 -0
  17. package/.claude/rules/features/ecs/systems.md +133 -0
  18. package/.claude/rules/features/ecs/transactions.md +45 -0
  19. package/.claude/rules/features/index.md +95 -0
  20. package/.claude/rules/features/services/index.md +34 -0
  21. package/.claude/rules/features/ui/index.md +31 -0
  22. package/.claude/rules/function-references.md +35 -0
  23. package/.claude/rules/lazy-element.md +127 -0
  24. package/.claude/rules/namespace.md +179 -0
  25. package/.claude/rules/plugin-modelling.md +170 -0
  26. package/.claude/rules/presentation.md +83 -0
  27. package/.claude/rules/type-casts.md +94 -0
  28. package/.claude-plugin/plugin.json +1 -1
  29. package/README.md +39 -81
  30. package/bin/cli.mjs +81 -26
  31. package/package.json +9 -2
  32. package/skills/build-actions/SKILL.md +14 -0
  33. package/skills/build-app-entry/SKILL.md +15 -0
  34. package/skills/build-application/SKILL.md +10 -0
  35. package/skills/build-computed/SKILL.md +14 -0
  36. package/skills/build-core-database/SKILL.md +24 -0
  37. package/skills/build-data/SKILL.md +18 -0
  38. package/skills/build-feature/SKILL.md +21 -0
  39. package/skills/build-game/SKILL.md +19 -0
  40. package/skills/build-indexes/SKILL.md +14 -0
  41. package/skills/build-service-database/SKILL.md +16 -0
  42. package/skills/build-services/SKILL.md +14 -0
  43. package/skills/build-systems/SKILL.md +24 -0
  44. package/skills/build-transactions/SKILL.md +15 -0
  45. package/skills/build-ui/SKILL.md +13 -0
  46. package/skills/meta-build/SKILL.md +43 -0
  47. package/skills/review/SKILL.md +25 -0
  48. package/skills/structure/SKILL.md +7 -0
  49. package/skills/x-alpha/SKILL.md +7 -0
  50. package/skills/x-beta/SKILL.md +7 -0
  51. package/skills/x-double/SKILL.md +7 -0
  52. package/skills/x-execute/SKILL.md +16 -0
  53. package/skills/x-log/SKILL.md +12 -0
  54. package/skills/x-pow/SKILL.md +9 -0
  55. package/skills/x-subagent/SKILL.md +8 -0
  56. package/skills/x-trace/SKILL.md +11 -0
  57. package/skills/x-validate/SKILL.md +67 -0
  58. package/skills/bar/SKILL.md +0 -8
  59. package/skills/foo/SKILL.md +0 -8
@@ -0,0 +1,94 @@
1
+ ---
2
+ paths:
3
+ - 'packages/**/*.ts'
4
+ - 'packages/**/*.tsx'
5
+ ---
6
+
7
+ # Type casts — only two valid uses
8
+
9
+ `as` is dangerous. It silently turns off the type checker for the cast
10
+ expression. Every cast is a place a future refactor can break in
11
+ silence. There are exactly two valid uses:
12
+
13
+ 1. **Proving a type the compiler cannot see.** A runtime invariant you
14
+ have established but TypeScript has no way to verify — e.g.
15
+ "validated JSON matches `User.schema`", "this `unknown` from a loose
16
+ API is `number` because the schema declared it", "this DOM node is
17
+ `HTMLInputElement` because the selector matched `input`".
18
+
19
+ 2. **Widening a literal or default to a useful container type.** A
20
+ resource or component default is `0` (the literal) without help.
21
+ `0 as F32` widens it to `F32` so the resource can hold any number,
22
+ not just zero. Same for `[] as User[]`, `false as boolean`,
23
+ `{} as State`. Without the cast, the inferred type is so narrow it
24
+ blocks every later assignment.
25
+
26
+ Anything else is the cast hiding a real defect. Most often: an identity
27
+ cast that neither narrows nor widens, used to make a type error go
28
+ away without fixing the underlying type.
29
+
30
+ ## The acceptance test
31
+
32
+ Before every `as`, articulate in one sentence which of the two it is:
33
+
34
+ - **Case 1:** "I know `<expr>` is `<T>` because <runtime invariant>."
35
+ - **Case 2:** "I'm widening `<literal>` so the container can hold any `<T>`."
36
+
37
+ If your sentence reduces to "TypeScript is wrong" or "I just want this
38
+ to compile", the cast is hiding a real defect — fix the type at its
39
+ source, do not cast at the consumer.
40
+
41
+ ## Common violations
42
+
43
+ ### Identity casts (neither widening nor narrowing)
44
+
45
+ ```ts
46
+ // ❌ `cameraAngle + delta` is already F32 (= number). Cast does nothing.
47
+ t.resources.cameraAngle = (t.resources.cameraAngle + delta) as F32;
48
+
49
+ // ✅
50
+ t.resources.cameraAngle = t.resources.cameraAngle + delta;
51
+ ```
52
+
53
+ ### Casting `any` to a specific shape just to call a property
54
+
55
+ ```ts
56
+ // ❌ `prev` is already any; the cast adds no information.
57
+ const n = (prev as ArrayLike<number>).length;
58
+
59
+ // ✅
60
+ const n = prev.length;
61
+ ```
62
+
63
+ ### Casting wider than necessary
64
+
65
+ ```ts
66
+ // ❌ Loses the value-side type for no reason.
67
+ const map = t.componentSchemas as Record<string, any>;
68
+
69
+ // ✅ Same key widening, but values stay typed as Schema.
70
+ const map = t.componentSchemas as Record<string, Schema>;
71
+ ```
72
+
73
+ ### Casting to silence an error you should fix at the source
74
+
75
+ ```ts
76
+ // declaration (your code)
77
+ export const emit = (name: string, payload: unknown): void => {
78
+ return inner.send(name, payload); // actually returns Promise<Ack>
79
+ };
80
+
81
+ // ❌ cast hides the lie; every caller will duplicate it
82
+ const ack = await (emit("save", data) as Promise<Ack>);
83
+
84
+ // ✅ fix the declaration once; every consumer benefits
85
+ export const emit = (name: string, payload: unknown): Promise<Ack> => {
86
+ return inner.send(name, payload);
87
+ };
88
+ ```
89
+
90
+ ## When the lying type is in code you control
91
+
92
+ Fix the declaration. A consumer-side cast is a leaky patch every other
93
+ caller will duplicate; one declaration change removes the cast
94
+ everywhere and protects future call sites the compiler will now catch.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adobe-data-ai",
3
- "version": "0.9.75",
3
+ "version": "0.9.84",
4
4
  "description": "Architecture skills for @adobe/data — data-oriented modelling, archetype iteration, hot-path performance, and related conventions.",
5
5
  "author": {
6
6
  "name": "Adobe"
package/README.md CHANGED
@@ -1,102 +1,60 @@
1
1
  # @adobe/data-ai
2
2
 
3
- Cross-agent architecture skills for [`@adobe/data`](https://www.npmjs.com/package/@adobe/data). One skill bundle, authored once, distributed two ways.
3
+ AI architecture skills + rules for building applications with
4
+ [`@adobe/data`](https://www.npmjs.com/package/@adobe/data) — a layered,
5
+ spec-first feature structure (`data → ecs → ui`) kept honest by conformance
6
+ tests. Versioned in lockstep with the library: `@adobe/data-ai@x.y.z` targets
7
+ `@adobe/data@x.y.z`.
4
8
 
5
- Skills version in lockstep with the library: `@adobe/data-ai@x.y.z` describes `@adobe/data@x.y.z`.
9
+ It installs two things:
6
10
 
7
- There are two distribution paths, one per agent family — they do **not** overlap:
11
+ - **skills** — `build-*` commands that scaffold features and applications.
12
+ - **rules** — the path-scoped conventions those skills follow while building.
8
13
 
9
- - **Claude Code → marketplace plugin** (see below). The installer never writes into `.claude/skills/`, so it can't collide with your own Claude skills.
10
- - **Cursor / Codex / other `.agents`-standard agents → `npx … install`** (below).
14
+ > **For the installing agent:** find the block below that matches your host
15
+ > (Claude Code or Cursor/other), run its commands, and stop. Each install owns a
16
+ > namespaced folder and is a clean wipe-and-recopy, so re-running is also how you
17
+ > **update** — it never touches files you authored.
11
18
 
12
- ## Install (Cursor, Codex, `.agents` agents)
19
+ ## Install — Claude Code
13
20
 
14
- The installer copies the skill folders into a single namespaced bundle directory that agents which recurse `.agents/skills/` discover:
15
-
16
- ```sh
17
- npx @adobe/data-ai@latest install
18
- ```
19
-
20
- This writes `.agents/skills/adobe-data-ai/<name>/SKILL.md` for each skill. The whole `adobe-data-ai/` directory belongs to this package, so a re-run is a clean wipe-and-recopy that never touches skills you authored elsewhere. Commit the result to share it with your team.
21
-
22
- Options:
23
-
24
- ```sh
25
- npx @adobe/data-ai@latest install --global # into ~/.agents/skills/adobe-data-ai/
26
- npx @adobe/data-ai@latest install --dir=./sub # into a specific base dir
27
- npx @adobe/data-ai@latest list # show bundled skills
28
- ```
29
-
30
- ## Install (Claude Code plugin)
31
-
32
- Claude Code does not scan `.agents/`; it consumes the skills as a native plugin from the `adobe/data` marketplace — no npm needed.
33
-
34
- Interactive:
21
+ Skills load as a marketplace plugin; rules install into the project.
35
22
 
36
23
  ```
37
24
  /plugin marketplace add adobe/data
38
25
  /plugin install adobe-data-ai@adobe-data-skills
26
+ npx @adobe/data-ai@latest install
39
27
  ```
40
28
 
41
- Or declaratively, so collaborators are prompted to auto-install on next launch — commit to your repo's `.claude/settings.json`:
42
-
43
- ```json
44
- {
45
- "extraKnownMarketplaces": {
46
- "adobe-data-skills": {
47
- "source": { "source": "github", "repo": "adobe/data" }
48
- }
49
- },
50
- "enabledPlugins": {
51
- "adobe-data-ai@adobe-data-skills": true
52
- }
53
- }
54
- ```
55
-
56
- The plugin cache is version-hashed and garbage-collected, so it is not a stable path to symlink against — prefer the `npx … install` copy model when you need a durable, cross-agent artifact.
29
+ - Skills → the `adobe-data-ai` plugin. **Update:** `/plugin` → update `adobe-data-ai`.
30
+ - Rules → `.claude/rules/adobe-data-ai/`. **Update:** re-run `npx @adobe/data-ai@latest install`.
57
31
 
58
- ---
32
+ ## Install — Cursor (and Codex / other `.agents` agents)
59
33
 
60
- # Pragmatic Programming
34
+ One command installs both:
61
35
 
62
- ## Target Audience
63
-
64
- Software engineers who want to build high quality applications with a sustainable velocity.
65
-
66
- ## Goals
67
-
68
- The goal of effective software engineers is to generate a high rate of value per unit time.
69
-
70
- rate = value / time
71
-
72
- We can improve the rate by either increasing value or decreasing time.
73
-
74
- - Quality: Write better applications. ▲value
75
- - Velocity: Write applications faster. ▼time
76
-
77
- ### Code Priorities
78
-
79
- 1. Correct: Does the job. This one is non-negotiable.
80
- 2. Clear: Easily understood by both humans and AI.
81
- 3. Changeable: Quickly and safely modified or extended.
82
-
83
- There is occasionally some tension between clarity and changeability. More abstraction or generic parameters may make things more changeable at the cost of some clarity.
84
-
85
- ### Code Challenges
36
+ ```
37
+ npx @adobe/data-ai@latest install
38
+ ```
86
39
 
87
- - Complexity: Undermines every single one of our code priorities.
40
+ - Skills → `.agents/skills/adobe-data-ai/`.
41
+ - Rules → `.claude/rules/adobe-data-ai/`.
42
+ - **Update:** re-run the same command.
88
43
 
89
- Complexity is the limiting factor which defines the upper limit on how sophisticated of an application we are able to create and maintain at a practical velocity.
44
+ ## Use
90
45
 
91
- The difficulty of dealing with complexity tends to increase at a greater than linear rate, especially once the short term context window of a human or ai agent is exceeded.
46
+ Ask your agent to run a build command — skills are available by name:
92
47
 
93
- ### General Principles
48
+ - **`build-application`** — build a whole app: a base feature that hosts
49
+ lazily-loaded peer features.
50
+ - **`build-feature`** — build one feature end to end. Pipes the per-layer skills
51
+ (`data → core-database → transactions → … → ui`), then conformance-tests the
52
+ result against its pure `data/` spec.
94
53
 
95
- - Separation of Concerns: If two concerns can be separated then do it.
96
- - Avoid mutation: Immutable values are easier to reason about.
97
- - Use Small files: Aim for less than 200 loc. Decompose if > 500 loc.
98
- - Single concern per file: Export only a single declaration per file.
99
- - Avoid object oriented classes: Combines data concerns with functions.
100
- - Distinguish services from data: Services do things, data stores things.
101
- - Use static typing: Finds errors earlier and guides both AI and humans.
102
- - Avoid side effects: Pure functions are easier to comprehend and test.
54
+ Both compose finer-grained skills that are installed alongside and discoverable
55
+ by name when you want a single phase or a specialized flow: `build-data`,
56
+ `build-core-database`, `build-indexes`, `build-transactions`, `build-computed`,
57
+ `build-services`, `build-service-database`, `build-actions`, `build-systems`,
58
+ `build-ui`, `build-app-entry`; plus `build-game`, `meta-build` (phase-by-phase
59
+ in subagents), `review` (audit output against the rules), and `structure`
60
+ (reason about layout).
package/bin/cli.mjs CHANGED
@@ -1,18 +1,21 @@
1
1
  #!/usr/bin/env node
2
- // Installer for the @adobe/data-ai skill bundle (Cursor / Codex / .agents-standard agents).
2
+ // Installer for the @adobe/data-ai bundle (Cursor / Codex / .agents-standard agents).
3
3
  //
4
- // Copies the SKILL.md folders shipped in this package into a single namespaced
5
- // bundle directory that agents which recurse `.agents/skills/` will discover:
4
+ // Lays down two managed, namespaced directories the agent discovers:
6
5
  //
7
- // .agents/skills/adobe-data-ai/<name>/SKILL.md
6
+ // .agents/skills/adobe-data-ai/<name>/SKILL.md — the build-* skills
7
+ // .claude/rules/adobe-data-ai/**/*.md — the architecture rules
8
8
  //
9
- // We own the `adobe-data-ai/` directory outright, so a refresh is a clean
10
- // wipe-and-recopy — it never touches skills you authored elsewhere.
9
+ // We own both `adobe-data-ai/` directories outright, so a refresh is a clean
10
+ // wipe-and-recopy — it never touches files you authored elsewhere. Re-running
11
+ // the installer is therefore also how you update.
11
12
  //
12
- // Claude Code is intentionally NOT a target: it does not scan `.agents/`, and
13
- // copying into `.claude/skills/` could collide with a user's own skills.
14
- // Claude consumes these as the `adobe-data-ai` marketplace plugin instead
15
- // (see README).
13
+ // Claude Code is intentionally NOT a skills target: it does not scan `.agents/`,
14
+ // and copying into `.claude/skills/` could collide with a user's own skills — it
15
+ // consumes the skills as the `adobe-data-ai` marketplace plugin instead. The
16
+ // rules, however, install into `.claude/rules/adobe-data-ai/` for every agent
17
+ // (Claude auto-injects them by their `paths:` globs; other agents read them by
18
+ // name as their skills run). See README.
16
19
 
17
20
  import {
18
21
  cpSync,
@@ -30,12 +33,39 @@ import { fileURLToPath } from "node:url";
30
33
  const here = dirname(fileURLToPath(import.meta.url));
31
34
  const pkgRoot = resolve(here, "..");
32
35
  const skillsSrc = join(pkgRoot, "skills");
36
+ const rulesSrc = join(pkgRoot, ".claude", "rules");
33
37
  const pkg = JSON.parse(readFileSync(join(pkgRoot, "package.json"), "utf8"));
34
38
  const { name: PKG_NAME, version: VERSION } = pkg;
35
39
 
36
- // Namespaced bundle folder — the whole directory belongs to this package.
40
+ // Namespaced bundle folder — the whole directory belongs to this package, under
41
+ // each agent root.
37
42
  const BUNDLE = "adobe-data-ai";
38
43
 
44
+ // A do-not-edit notice dropped at each bundle root. Claude Code loads nested
45
+ // CLAUDE.md files when working in a subtree, so an agent that opens one of these
46
+ // folders sees the notice before touching anything. `extra` adds a pointer to
47
+ // the companion bundle.
48
+ function notice(extra) {
49
+ return `# Externally managed — do not edit
50
+
51
+ The files in this folder are installed and managed by the \`${PKG_NAME}\`
52
+ package. This entire directory is **deleted and rebuilt** on every
53
+ \`npx ${PKG_NAME} install\`, so any local edit here is silently discarded on the
54
+ next reinstall or version upgrade.
55
+
56
+ To change them, edit upstream in the \`${PKG_NAME}\` package and publish a new
57
+ version, then reinstall — do not modify these files in place.
58
+ ${extra ? `\n${extra}\n` : ""}`;
59
+ }
60
+
61
+ function writeMeta(bundleDir, noticeBody, extraMeta) {
62
+ writeFileSync(join(bundleDir, "CLAUDE.md"), noticeBody);
63
+ writeFileSync(
64
+ join(bundleDir, ".data-ai.json"),
65
+ JSON.stringify({ package: PKG_NAME, version: VERSION, ...extraMeta }, null, 2) + "\n",
66
+ );
67
+ }
68
+
39
69
  function discoverSkills() {
40
70
  if (!existsSync(skillsSrc)) return [];
41
71
  return readdirSync(skillsSrc, { withFileTypes: true })
@@ -44,17 +74,41 @@ function discoverSkills() {
44
74
  .sort();
45
75
  }
46
76
 
47
- function installTo(bundleDir, skills) {
48
- // We own this directory — wipe and recopy for a clean refresh.
77
+ // Recursively count the rule `.md` files, excluding the top-level README.md
78
+ // (rules-authoring meta doc, not a rule — and it carries no `paths:` guard).
79
+ function countRules(dir) {
80
+ let n = 0;
81
+ for (const d of readdirSync(dir, { withFileTypes: true })) {
82
+ if (d.isDirectory()) n += countRules(join(dir, d.name));
83
+ else if (d.name.endsWith(".md") && !(dir === rulesSrc && d.name === "README.md")) n += 1;
84
+ }
85
+ return n;
86
+ }
87
+
88
+ function installSkills(base, skills) {
89
+ const bundleDir = join(base, ".agents", "skills", BUNDLE);
49
90
  rmSync(bundleDir, { recursive: true, force: true });
50
91
  mkdirSync(bundleDir, { recursive: true });
51
92
  for (const name of skills) {
52
93
  cpSync(join(skillsSrc, name), join(bundleDir, name), { recursive: true });
53
94
  }
54
- writeFileSync(
55
- join(bundleDir, ".data-ai.json"),
56
- JSON.stringify({ package: PKG_NAME, version: VERSION, skills }, null, 2) + "\n",
95
+ writeMeta(
96
+ bundleDir,
97
+ notice("The architecture rules these skills follow are installed at\n`.claude/rules/adobe-data-ai/` (referenced by name from each SKILL.md)."),
98
+ { skills },
57
99
  );
100
+ return bundleDir;
101
+ }
102
+
103
+ function installRules(base) {
104
+ const bundleDir = join(base, ".claude", "rules", BUNDLE);
105
+ rmSync(bundleDir, { recursive: true, force: true });
106
+ mkdirSync(bundleDir, { recursive: true });
107
+ // Copy the whole rules tree, minus the top-level README.md meta doc.
108
+ const readme = join(rulesSrc, "README.md");
109
+ cpSync(rulesSrc, bundleDir, { recursive: true, filter: (src) => src !== readme });
110
+ writeMeta(bundleDir, notice(), { rules: countRules(rulesSrc) });
111
+ return bundleDir;
58
112
  }
59
113
 
60
114
  function parseArgs(argv) {
@@ -72,19 +126,20 @@ function parseArgs(argv) {
72
126
 
73
127
  const HELP = `${PKG_NAME} v${VERSION}
74
128
 
75
- Install the architecture-skill bundle for Cursor, Codex, and other agents
76
- that scan .agents/skills/. (Claude Code uses the marketplace plugin instead.)
129
+ Install the architecture skills + rules for Cursor, Codex, and other agents.
130
+ (Claude Code gets the skills from the marketplace plugin; the rules install the
131
+ same way for every agent — see README.)
77
132
 
78
133
  Usage:
79
134
  npx ${PKG_NAME}@latest install [options]
80
135
  npx ${PKG_NAME}@latest list
81
136
 
82
137
  Commands:
83
- install Copy skills into .agents/skills/${BUNDLE}/ (default).
138
+ install Skills → .agents/skills/${BUNDLE}/, rules → .claude/rules/${BUNDLE}/ (default).
84
139
  list Print the skills bundled in this package.
85
140
 
86
141
  Options:
87
- --global, -g Install into your home directory (~/.agents/skills/${BUNDLE}/)
142
+ --global, -g Install into your home directory (~/.agents, ~/.claude)
88
143
  instead of the current project.
89
144
  --dir=<path> Base directory to install into (default: cwd).
90
145
  --help, -h Show this help.
@@ -119,13 +174,13 @@ function main() {
119
174
  }
120
175
 
121
176
  const base = flags.has("global") ? homedir() : dir ? resolve(dir) : process.cwd();
122
- const bundleDir = join(base, ".agents", "skills", BUNDLE);
123
-
124
- installTo(bundleDir, skills);
177
+ const skillsDir = installSkills(base, skills);
178
+ const rulesDir = installRules(base);
179
+ const ruleCount = countRules(rulesSrc);
125
180
 
126
- process.stdout.write(`Installed ${skills.length} skill(s) from ${PKG_NAME} v${VERSION}\n`);
127
- process.stdout.write(` ${bundleDir}\n`);
128
- process.stdout.write(`Skills: ${skills.join(", ")}\n`);
181
+ process.stdout.write(`Installed ${PKG_NAME} v${VERSION}\n`);
182
+ process.stdout.write(` ${skills.length} skills → ${skillsDir}\n`);
183
+ process.stdout.write(` ${ruleCount} rules → ${rulesDir}\n`);
129
184
  }
130
185
 
131
186
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/data-ai",
3
- "version": "0.9.83",
3
+ "version": "0.9.84",
4
4
  "description": "Cross-agent architecture skills for @adobe/data — installable as a Claude Code plugin or copied into any Agent-Skills-compatible agent (Cursor, Codex).",
5
5
  "type": "module",
6
6
  "private": false,
@@ -13,6 +13,7 @@
13
13
  },
14
14
  "files": [
15
15
  "skills",
16
+ ".claude",
16
17
  "bin",
17
18
  ".claude-plugin",
18
19
  "README.md",
@@ -27,12 +28,18 @@
27
28
  "codex",
28
29
  "skills"
29
30
  ],
31
+ "peerDependencies": {
32
+ "@adobe/data": "0.9.84"
33
+ },
30
34
  "devDependencies": {
31
- "vitest": "^1.6.0"
35
+ "typescript": "^5.8.3",
36
+ "vitest": "^1.6.0",
37
+ "@adobe/data": "0.9.84"
32
38
  },
33
39
  "license": "MIT",
34
40
  "scripts": {
35
41
  "build": "cp ../../LICENSE .",
42
+ "typecheck": "true",
36
43
  "test": "vitest --run --passWithNoTests",
37
44
  "publish-public": "pnpm build && pnpm publish --no-git-checks --access public"
38
45
  }
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: build-actions
3
+ description: Build a feature's ecs action-database — async orchestration over services and transactions. If the feature has async flows.
4
+ input: feature
5
+ output: feature
6
+ ---
7
+
8
+ Create `ecs/action-database/`: `action-database.ts` (extends `ServiceDatabase`, adds `actions`
9
+ from `./actions/index.js`) plus an `actions/` folder — one async orchestrator per file. An action
10
+ takes `db: ServiceDatabase`, awaits `services/` ports, then commits **exactly one** transaction.
11
+
12
+ The top ecs layer; comes after `service-database`.
13
+
14
+ The how is in the auto-loading `features/ecs/actions.md` rule.
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: build-app-entry
3
+ description: Wire built features into a running application — import peer schemas, lazy-load peers, and mount the root UI.
4
+ input: app
5
+ output: app
6
+ ---
7
+
8
+ - The base (`features/main`) core-database `imports` each peer feature's core-database
9
+ plugin, so all schemas coexist, persist, and sync while the base type stays decoupled.
10
+ - The base reaches a peer only through a lazy element wrapper (dynamic import), so peers
11
+ load on demand.
12
+ - The entry point creates the live database from `FeatureDatabase.plugin` (the base
13
+ feature's assembled database — see `features/ecs/index.md`) and mounts the root UI.
14
+
15
+ See `features/index.md` (one-app-many-features) for the wiring rules.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: build-application
3
+ description: Build an application — a base feature hosting lazily-loaded peer features.
4
+ input: app
5
+ output: app
6
+ ---
7
+
8
+ /build-feature (base — features/main)
9
+ |> /build-feature (each peer feature)
10
+ |> /build-app-entry
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: build-computed
3
+ description: Build a feature's ecs computed-database — derived observable values.
4
+ input: feature
5
+ output: feature
6
+ ---
7
+
8
+ Create `ecs/computed-database/`: `computed-database.ts` (extends the previous layer, adds
9
+ `computed` from `./computed/index.js`) plus a `computed/` folder — one `cached` derived value
10
+ per file + barrel. Derivation logic lives in `data/`; a computed only wires a db observable to it.
11
+
12
+ Comes after `transaction-database`.
13
+
14
+ The how is in the auto-loading `features/ecs/computed.md` rule.
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: build-core-database
3
+ description: Build a feature's ecs schema — the core-database (components, resources, archetypes). The first ecs layer.
4
+ input: feature
5
+ output: feature
6
+ ---
7
+
8
+ Create `ecs/core-database/` — `core-database.ts` plus one single-export file per facet
9
+ the feature actually uses (`components`, `resources`, `archetypes` are each optional on
10
+ `Database.Plugin.create`). Create only the facet files you need; omit the rest rather than
11
+ shipping empty `Database.components({})` boilerplate. A feature with **no entities** (a
12
+ singleton whose whole state is resources) is just `resources.ts` + `core-database.ts`.
13
+
14
+ - `components.ts` → `Database.components({ document, settings, presence, session })` (scopes optional) — only if the feature has entities.
15
+ - `resources.ts` → `Database.resources({ … })` (every entry needs a `default`) — for singleton / global state.
16
+ - `archetypes.ts` → `Database.archetypes(components, { … })` — only alongside components.
17
+ - `core-database.ts` → `Database.Plugin.create({ imports?, components?, resources?, archetypes? })`, exporting the `CoreDatabase` namespace.
18
+
19
+ The schema root; comes after `data/` (and `services/`). Bind each schema from its `data/`
20
+ type — don't author shapes here. Components use JSON schemas; resources use the
21
+ `{ default }` convention (a schemaless aggregate binds via `{ default: State.create() }`).
22
+
23
+ The how is in the auto-loading `features/ecs/index.md` + `components.md` / `resources.md` /
24
+ `archetypes.md` rules.
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: build-data
3
+ description: Build a feature's data/ layer — data-type namespaces and the State spec. The first, foundational feature phase.
4
+ input: feature
5
+ output: feature
6
+ ---
7
+
8
+ Create the feature's `data/` layer (pure spec; depends on nothing but `@adobe/data`
9
+ and other `data/` declarations):
10
+
11
+ - one namespace folder per data type — `<type>/{<type>.ts, schema.ts, public.ts, <helper>.ts}`;
12
+ - `data/state/` — the `State` aggregate plus its pure transforms/derivations.
13
+
14
+ The schema is the single source of truth; the type derives from it (`Schema.ToType`).
15
+ Helpers are pure and unit-tested. Run this first — every other layer imports `data/`.
16
+
17
+ The how is in the auto-loading rules: `features/data/index.md`, `features/data/state.md`, and
18
+ `namespace.md`.
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: build-feature
3
+ description: Build a complete feature by piping the per-layer build-* skills bottom-up.
4
+ input: feature
5
+ output: feature
6
+ ---
7
+
8
+ /build-data
9
+ |> /build-services
10
+ |> /build-core-database
11
+ |> /build-indexes
12
+ |> /build-transactions
13
+ |> /build-computed
14
+ |> /build-systems
15
+ |> /build-service-database
16
+ |> /build-actions
17
+ |> /build-ui
18
+
19
+ Run with /x-execute. Each step is a no-op for a layer the feature doesn't use
20
+ (`build-systems` only for real-time features; `build-services` / `build-service-database` /
21
+ `build-actions` only when the feature has async flows).
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: build-game
3
+ description: Build a game — an application whose features model game state, rules, and rendering.
4
+ input: game
5
+ output: game
6
+ ---
7
+
8
+ /build-application — a game is an application.
9
+
10
+ Map game concepts to feature layers: data/ = state + rules (+ per-tick step math),
11
+ components/archetypes = entity kinds, indexes = spatial/lookup queries,
12
+ transactions = moves/spawns, computed = score/status/winner, ui = view + input.
13
+
14
+ - **Turn-based** uses the reactive transaction → computed → ui loop, no systems
15
+ (see data-lit-tictactoe).
16
+ - **Real-time** adds the `build-systems` phase: a per-frame tick loop (movement,
17
+ collision, lifetime) driven by the scheduler, over many entities in distinct
18
+ archetypes. This is where components, archetypes, indexes, and systems all
19
+ carry real weight — see `features/ecs/systems.md`.
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: build-indexes
3
+ description: Build a feature's ecs index-database — component/archetype indexes for O(1) lookup. As needed.
4
+ input: feature
5
+ output: feature
6
+ ---
7
+
8
+ Create `ecs/index-database/`: `index-database.ts` (extends `CoreDatabase`, adds the `indexes`
9
+ facet from `./indexes/index.js`) plus an `indexes/` folder — one index per file + an `index.ts`
10
+ barrel.
11
+
12
+ Only if the feature needs indexed lookups. Comes after `core-database`.
13
+
14
+ The how is in the auto-loading `features/ecs/indexes.md` rule.
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: build-service-database
3
+ description: Build a feature's ecs service-database — db-bound service factories. If the feature exposes services.
4
+ input: feature
5
+ output: feature
6
+ ---
7
+
8
+ Create `ecs/service-database/`: `service-database.ts` (extends the previous layer, registers the
9
+ `services` facet). Two forms:
10
+
11
+ - db-bound factories `create<Name>Service(db, …)` in `service-database/services/` (one per file + barrel), for services that read `db.observe.*` / call `db.transactions.*`; or
12
+ - plain async ports registered straight from the feature's `services/` contracts.
13
+
14
+ Comes after `computed-database`.
15
+
16
+ The how is in the auto-loading `features/ecs/services.md` rule.
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: build-services
3
+ description: Build a feature's services/ layer — async capability contracts (ports to the outside world). Optional.
4
+ input: feature
5
+ output: feature
6
+ ---
7
+
8
+ Create the feature's `services/` layer: one `<name>-service/` namespace folder per async
9
+ contract — an `interface` (validated with `AsyncDataService.IsValid`), async-only members,
10
+ and `create*` factories.
11
+
12
+ Only if the feature talks to the outside world. Comes after `data/`, before `ecs/`.
13
+
14
+ The how is in the auto-loading `features/services/index.md` rule (and `namespace.md`).