@adobe/data-ai 0.9.89 → 0.9.91

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 (42) hide show
  1. package/.claude/rules/README.md +22 -16
  2. package/.claude/rules/element.md +1 -1
  3. package/.claude/rules/features/data/index.md +1 -1
  4. package/.claude/rules/features/data/state.md +2 -2
  5. package/.claude/rules/features/index.md +56 -39
  6. package/.claude/rules/features/services/index.md +31 -18
  7. package/.claude/rules/features/{ecs → services/main-service}/actions.md +2 -2
  8. package/.claude/rules/features/{ecs → services/main-service}/archetypes.md +1 -1
  9. package/.claude/rules/features/{ecs → services/main-service}/components.md +2 -2
  10. package/.claude/rules/features/{ecs → services/main-service}/computed.md +1 -1
  11. package/.claude/rules/features/{ecs → services/main-service}/conformance.md +3 -3
  12. package/.claude/rules/features/{ecs → services/main-service}/index.md +10 -8
  13. package/.claude/rules/features/{ecs → services/main-service}/indexes.md +1 -1
  14. package/.claude/rules/features/{ecs → services/main-service}/resources.md +2 -2
  15. package/.claude/rules/features/{ecs → services/main-service}/services.md +1 -1
  16. package/.claude/rules/features/{ecs → services/main-service}/systems.md +8 -4
  17. package/.claude/rules/features/{ecs → services/main-service}/transactions.md +3 -3
  18. package/.claude/rules/features/ui/binding-element.md +2 -2
  19. package/.claude/rules/features/ui/index.md +1 -1
  20. package/.claude-plugin/plugin.json +1 -1
  21. package/README.md +1 -1
  22. package/bin/cli.mjs +51 -3
  23. package/package.json +4 -5
  24. package/skills/build-actions/SKILL.md +4 -4
  25. package/skills/build-app-entry/SKILL.md +1 -1
  26. package/skills/build-computed/SKILL.md +3 -3
  27. package/skills/build-core-database/SKILL.md +3 -3
  28. package/skills/build-data/SKILL.md +1 -1
  29. package/skills/build-game/SKILL.md +1 -1
  30. package/skills/build-indexes/SKILL.md +3 -3
  31. package/skills/build-service-database/SKILL.md +3 -3
  32. package/skills/build-services/SKILL.md +2 -2
  33. package/skills/build-systems/SKILL.md +8 -5
  34. package/skills/build-transactions/SKILL.md +4 -3
  35. package/skills/build-ui/SKILL.md +1 -1
  36. package/skills/meta-build/SKILL.md +1 -0
  37. package/skills/review/SKILL.md +1 -0
  38. /package/.claude/rules/{cohesion.md → global/cohesion.md} +0 -0
  39. /package/.claude/rules/{function-references.md → global/function-references.md} +0 -0
  40. /package/.claude/rules/{namespace.md → global/namespace.md} +0 -0
  41. /package/.claude/rules/{react.md → global/react.md} +0 -0
  42. /package/.claude/rules/{type-casts.md → global/type-casts.md} +0 -0
@@ -13,30 +13,36 @@ folder's own `index.md` holds just enough to understand that folder; each
13
13
  child gets its own file (recursing wherever the source tree does):
14
14
 
15
15
  ```
16
+ global/ # always-on conventions — deliberately repo-wide globs
17
+ namespace.md cohesion.md type-casts.md function-references.md react.md
16
18
  features/
17
- index.md # the feature layering as a whole (ui → ecs → services → data)
19
+ index.md # the feature layering as a whole (ui → services → data)
18
20
  data/
19
21
  index.md # data-type namespaces (foundation)
20
22
  state.md # the State aggregate: pure transforms & derivations
21
- services/index.md # service interfaces + service types
22
- ecs/
23
- index.md # the ECS layer + layered database plugins
24
- components.md resources.md archetypes.md
25
- computed.md indexes.md transactions.md services.md actions.md
26
- systems.md conformance.md
23
+ services/
24
+ index.md # the services layer: main-service + capability contracts
25
+ main-service/ # the feature service (ECS implementation)
26
+ index.md # the service + its layered database plugins
27
+ components.md resources.md archetypes.md
28
+ computed.md indexes.md transactions.md services.md actions.md
29
+ systems.md conformance.md
27
30
  ui/index.md # UI (points to element / presentation / lazy-element file rules)
28
31
  ```
29
32
 
30
- Alongside `features/`, the rules-root `.md` files hold the **cross-cutting**
31
- patterns the feature rules reference — `namespace.md`, `data-modelling.md`,
32
- `type-casts.md`, `function-references.md`, `cohesion.md`, `archetypes.md` (row
33
- iteration), `plugin-modelling.md`, and the UI file rules (`element.md`,
34
- `lazy-element.md`, `presentation.md`). They live here so the bundle is self-contained; this repo
35
- symlinks them into its own `.claude/rules/` (as it does `features/`).
33
+ The `global/` rules (`namespace.md`, `cohesion.md`, `type-casts.md`,
34
+ `function-references.md`, `react.md`) are **intentionally repo-wide** — their
35
+ `paths:` globs (`**/*.ts` etc.) apply everywhere, by design, so the folder name
36
+ makes that explicit. Alongside `features/`, the remaining rules-root `.md` files
37
+ hold the other **cross-cutting** patterns the feature rules reference —
38
+ `data-modelling.md`, `archetypes.md` (row iteration), `plugin-modelling.md`, and
39
+ the UI file rules (`element.md`, `lazy-element.md`, `presentation.md`). They live
40
+ here so the bundle is self-contained; this repo symlinks them into its own
41
+ `.claude/rules/` (as it does `features/`).
36
42
 
37
43
  Each rule's `paths:` glob is scoped to `**/features/*/<layer>/…`, so these
38
44
  rules apply only once an application opts into the feature-folder pattern
39
45
  (source organized under `features/<name>/`). Editing
40
- `features/<name>/ecs/<layer>-database/components/foo.ts` pulls in both
41
- `ecs/index.md` (the layer overview) and `ecs/components.md` (the specifics) —
42
- at creation and at every later edit.
46
+ `features/<name>/services/main-service/core-database/components.ts` pulls in both
47
+ `main-service/index.md` (the layer overview) and `main-service/components.md`
48
+ (the specifics) — at creation and at every later edit.
@@ -124,7 +124,7 @@ Lit-only: `static styles = styles` from a sibling `*.css.ts`. `@property`
124
124
  exists *only* for locator inputs — never for state, never for derived
125
125
  values, never for parent-forwarded flags. The `P` in `DatabaseElement<P>` (and
126
126
  the `get plugin()` it returns) is the surface the element *consumes* — never the
127
- varying topmost-layer name (see `features/ecs/index.md`): `typeof
127
+ varying topmost-layer name (see `features/services/main-service/index.md`): `typeof
128
128
  FeatureDatabase.plugin` for a self-contained feature. **Exception:** an element
129
129
  meant to be *extended* — injected with various databases that build on this
130
130
  feature (a peer app that adds an agent, a p2p/presence build) — types on the
@@ -11,7 +11,7 @@ communication over the wire — no functions, no handles, just plain data.
11
11
  It depends on nothing but `@adobe/data` and other `data/` declarations, and
12
12
  needs no knowledge of anything built on top of it.
13
13
 
14
- Each data type is its own namespace folder (see `namespace.md`), holding
14
+ Each data type is its own namespace folder (see `global/namespace.md`), holding
15
15
  its schema, its derived type, and its pure synchronous helpers together:
16
16
 
17
17
  ```
@@ -43,8 +43,8 @@ export * as State from "./public.js";
43
43
  - Each transform has a sibling `*.test.ts`; performance is irrelevant here,
44
44
  correctness is everything. Keep its cases in a sibling `<transform>.cases.ts`
45
45
  typed `ConformanceCase<Args>[]` (the shared `conformance-case.ts` type) —
46
- spec-owned truth the matching ecs conformance test imports unchanged (see
47
- `ecs/conformance.md`). Author `before`/`after` as full `State`
46
+ spec-owned truth the matching main-service conformance test imports unchanged (see
47
+ `services/main-service/conformance.md`). Author `before`/`after` as full `State`
48
48
  (`{ ...State.create(), …overrides }`); the generic-slice signature lets them
49
49
  flow through. Tolerant full-`State` equality is the shared
50
50
  `expect-state-matches.ts`, alongside the cases here.
@@ -2,7 +2,6 @@
2
2
  paths:
3
3
  - '**/features/*/data/**/*.ts'
4
4
  - '**/features/*/services/**/*.ts'
5
- - '**/features/*/ecs/**/*.ts'
6
5
  - '**/features/*/ui/**/*.ts'
7
6
  ---
8
7
 
@@ -14,34 +13,39 @@ trust, and an **efficient implementation** proven equivalent to it.
14
13
  - **`data/` is the specification.** The whole feature modelled as one immutable
15
14
  `State` with pure transformations over it — correct by construction, fully
16
15
  unit-tested, performance irrelevant. This is the source of truth.
17
- - **`ecs/` is the implementation.** The same model physically arranged for
18
- mutation efficiency (a reactive Entity-Component-System). Its reads and writes
19
- wrap the `data/` functions where practical; where they must be hand-optimized,
20
- unit tests verify they still agree with the `data/` precedent.
16
+ - **`services/main-service/` is the implementation.** The same model physically
17
+ arranged for mutation efficiency — a reactive Entity-Component-System, an
18
+ implementation detail behind the service. Its reads and writes wrap the
19
+ `data/` functions where practical; where they must be hand-optimized, unit
20
+ tests verify they still agree with the `data/` precedent.
21
21
 
22
- Because the optimized `ecs/` layer is largely mechanical given the `data/` spec,
23
- it can be generated and kept honest by AI rules, with the conformance tests as
24
- the safety net. Net result: write a slow-but-verifiable app, then derive a fast
25
- one that provably behaves the same.
22
+ Because the optimized `main-service` is largely mechanical given the `data/`
23
+ spec, it can be generated and kept honest by AI rules, with the conformance
24
+ tests as the safety net. Net result: write a slow-but-verifiable app, then
25
+ derive a fast one that provably behaves the same.
26
26
 
27
- ## The four layers
27
+ ## The layers
28
28
 
29
- `ui → ecs → services → data` — higher imports lower, never the reverse. `data/`
29
+ `ui → services → data` — higher imports lower, never the reverse. `data/`
30
30
  depends on nothing but `@adobe/data` and other `data/` declarations. A feature
31
31
  creates only the layers it uses.
32
32
 
33
33
  | Layer | Role |
34
34
  |-------|------|
35
35
  | `data/` | The spec: `State`, pure transforms & derivations, entity sub-types. Pure, tested. |
36
- | `services/` | Async capability contracts (ports to the outside world). Optional. |
37
- | `ecs/` | The implementation: the ECS materialisation + reactive reads/writes over it. |
36
+ | `services/main-service/` | The implementation: the ECS materialisation + reactive reads/writes. The **sole entrypoint** — the only service the `ui/` binds to. |
37
+ | `services/<name>-service/` | Async capability contracts (ports to the outside world). Reached only *through* `main-service` (its actions/services wire them in), never by the UI. Optional. |
38
38
  | `ui/` | Presentation. |
39
39
 
40
+ `services/` holds two kinds of service: the one `main-service/` (ECS-backed
41
+ state, its own subtree of rules) and any async capability contracts. The UI, and
42
+ every external consumer, sees only `main-service`.
43
+
40
44
  ## One app, many features
41
45
 
42
46
  An application is a set of **features**, each its own `features/<name>/` folder
43
- with the same four layers. One base feature (`features/main/`) is the host; the
44
- rest are peers that load lazily.
47
+ with the same layers. One base feature (`features/main/`) is the host; the rest
48
+ are peers that load lazily.
45
49
 
46
50
  **Keep each feature small; grow by adding features, not by bloating one.** A
47
51
  feature is meant to fit in the head — a handful of files per layer. When a
@@ -53,16 +57,17 @@ its own peer feature rather than let one feature's folders balloon.
53
57
  base must not depend on its children — with one sanctioned exception below.
54
58
  - **The base `imports` every peer's *schema* plugin** —
55
59
  `Database.Plugin.create({ imports })`, not `extends`. `imports` merges the
56
- peer's `core-database` (components / resources / archetypes) into the shared
57
- store at runtime **without** pulling its types or behavior into the base's type
58
- or bundle (`extends` would do both, and cost quadratically). So one store knows
59
- every feature's schema — data coexists, persists, and syncs — while the base
60
- stays decoupled. Import the peer's `core-database.ts` plugin (schema only) —
61
- under its feature-qualified name `<Peer>CoreDatabase` (see the cross-feature
62
- naming rule in `ecs/index.md`): its indexes, transactions, computed, services,
63
- and UI stay out until the feature loads. A column two features share (e.g.
64
- `name`) lives in `data/` and is referenced by identity, so `combinePlugins`
65
- dedupes it.
60
+ peer's `services/main-service/core-database` (components / resources /
61
+ archetypes) into the shared store at runtime **without** pulling its types or
62
+ behavior into the base's type or bundle (`extends` would do both, and cost
63
+ quadratically). So one store knows every feature's schema — data coexists,
64
+ persists, and syncs — while the base stays decoupled. Import the peer's
65
+ `services/main-service/core-database.ts` plugin (schema only) — under its
66
+ feature-qualified name `<Peer>CoreDatabase` (see the cross-feature naming rule
67
+ in `services/main-service/index.md`): its indexes, transactions, computed,
68
+ services, and UI stay out until the feature loads. A column two features share
69
+ (e.g. `name`) lives in `data/` and is referenced by identity, so
70
+ `combinePlugins` dedupes it.
66
71
  - **Peers load lazily by being used.** `DatabaseElement`, on connect, walks up to
67
72
  the nearest ancestor database and `extend`s it with its own plugin — so the
68
73
  first time a feature element renders, its full plugin (indexes, transactions,
@@ -71,25 +76,37 @@ its own peer feature rather than let one feature's folders balloon.
71
76
  load is genuinely on-demand.
72
77
  - **The base reaches a child only through a lazy element wrapper** — a tiny
73
78
  `Foo()` that `void import()`s the child element. That dynamic import is the one
74
- allowed core→child seam; the heavy element and its service database stay in the
79
+ allowed core→child seam; the heavy element and its main-service stay in the
75
80
  child's own chunk.
76
81
 
77
82
  ## Spec and implementation, kept honest
78
83
 
79
- The tie between `data/` (spec) and `ecs/` (implementation) is **conformance**,
80
- one property — `toState(apply(fromState(before), args)) ≡ transform(before, args)`:
81
- each ecs mutation, seeded and read back through a test-only `ecs ↔ State`
84
+ The tie between `data/` (spec) and `main-service` (implementation) is
85
+ **conformance**, one property —
86
+ `toState(apply(fromState(before), args)) ≡ transform(before, args)`: each
87
+ main-service mutation, seeded and read back through a test-only store↔`State`
82
88
  projection, equals the pure `data/` transform it stands for. The projection and
83
- its runner live in `ecs/conformance/` (see `ecs/conformance.md`); the shared
84
- `{ before, args, after }` cases are spec-owned (`data/state/<transform>.cases.ts`),
85
- so conforming the ecs path is "substitute the implementation, reuse the
86
- expectations." This lets the ecs layer be largely mechanical and agent-generated,
87
- with the spec as oracle. *How* to author each layer lives in the per-folder rules
88
- below.
89
+ its runner live in `services/main-service/conformance/` (see
90
+ `services/main-service/conformance.md`); the shared `{ before, args, after }`
91
+ cases are spec-owned (`data/state/<transform>.cases.ts`), so conforming the
92
+ implementation is "substitute the implementation, reuse the expectations." This
93
+ lets `main-service` be largely mechanical and agent-generated, with the spec as
94
+ oracle. *How* to author each layer lives in the per-folder rules below.
95
+
96
+ ## Reference implementations
97
+
98
+ Working samples ship inside `@adobe/data` at
99
+ `node_modules/@adobe/data/references/<sample>/src/` — read them for concrete,
100
+ current examples of this structure. `data-lit-todo` is the most complete
101
+ (multi-feature, capability services, indexes, conformance tests);
102
+ `data-lit-tictactoe` is the minimal turn-based reference.
89
103
 
90
104
  ## Per-layer detail
91
105
 
92
- See the rules under each folder: `data/`, `services/`, `ecs/` (components,
93
- resources, archetypes, computed, indexes, transactions), `ui/`. Cross-cutting
94
- patterns live at the rules root — `namespace.md`, `data-modelling.md`,
95
- `archetypes.md` (row iteration), `type-casts.md`, `cohesion.md`.
106
+ See the rules under each folder: `data/`, `services/` — the `main-service/`
107
+ subtree (components, resources, archetypes, computed, indexes, transactions,
108
+ systems, conformance) and capability-contract services — and `ui/`.
109
+ Always-on conventions live in `global/` (`namespace.md`, `cohesion.md`,
110
+ `type-casts.md`, `function-references.md`, `react.md` — deliberately repo-wide);
111
+ other cross-cutting patterns at the rules root — `data-modelling.md`,
112
+ `archetypes.md` (row iteration).
@@ -3,32 +3,45 @@ paths:
3
3
  - '**/features/*/services/**/*.ts'
4
4
  ---
5
5
 
6
- # services/ — async capability contracts
6
+ # services/ — the feature's services
7
7
 
8
- Async ports: processing, persistence, observation, generation. A service
9
- is the boundary between pure feature code and the outside world, which is
10
- why its members are async — enabling cross-process portability and lazy
11
- loading (`AsyncDataService.createLazy`).
8
+ Everything a feature exposes as a service lives here. Two kinds:
12
9
 
13
- This layer holds **service interfaces**, one per `<name>-service/` folder;
14
- the export and folder both carry the `-service` suffix. Each is a
15
- namespace folder (`namespace.md`).
10
+ - **`main-service/`** — the one entrypoint. The ECS-backed reactive state
11
+ service (materialisation + reads/writes over it); the only service the `ui/`
12
+ and external consumers bind to. It has its own subtree of rules
13
+ (`main-service/index.md` and the layer files under it). Every feature with
14
+ state has exactly one.
15
+ - **`<name>-service/`** — async **capability contracts**: ports to the outside
16
+ world (processing, persistence, observation, generation). Reached only
17
+ *through* `main-service` (its service/action layers wire them in), never by the
18
+ UI. A feature has zero or more.
16
19
 
17
- - The contract is an `interface` — the only place `interface` is used in
18
- the codebase — validated immediately with
20
+ The rest of this rule governs the capability contracts; `main-service` follows
21
+ its own subtree.
22
+
23
+ ## Capability contracts
24
+
25
+ Each is a namespace folder (`global/namespace.md`); the export and folder both carry the
26
+ `-service` suffix. A service is the boundary between pure feature code and the
27
+ outside world, which is why its members are async — enabling cross-process
28
+ portability and lazy loading (`AsyncDataService.createLazy`).
29
+
30
+ - The contract is an `interface` — the only place `interface` is used in the
31
+ codebase — validated immediately with
19
32
  `Assert<AsyncDataService.IsValid<typeof MyService>>`.
20
33
  - Members are async only: `void | Promise<T> | AsyncGenerator<T> | Observe<T>`.
21
34
  - Provide `create*` factories.
22
35
 
23
36
  ## Where the I/O types live
24
37
 
25
- Most input/output types belong to a single service — declare them **on
26
- that service's namespace** (`MyService.SomeInput`) and expose them only
27
- when something external actually references them; not everything does.
38
+ Most input/output types belong to a single service — declare them **on that
39
+ service's namespace** (`MyService.SomeInput`) and expose them only when something
40
+ external actually references them; not everything does.
28
41
 
29
- A **service type** may be non-serializable (callbacks, function
30
- signatures) — that's what distinguishes it from a `data/` type. If an I/O
31
- value is a plain serializable value, prefer a `data/` type instead.
42
+ A **service type** may be non-serializable (callbacks, function signatures) —
43
+ that's what distinguishes it from a `data/` type. If an I/O value is a plain
44
+ serializable value, prefer a `data/` type instead.
32
45
 
33
- A non-service type sits *directly* in `services/` **only** when it is
34
- genuinely shared across more than one service — rare, but it happens.
46
+ A non-service type sits *directly* in `services/` **only** when it is genuinely
47
+ shared across more than one service — rare, but it happens.
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  paths:
3
- - '**/features/*/ecs/**/actions/**/*.ts'
3
+ - '**/features/*/services/main-service/**/actions/**/*.ts'
4
4
  ---
5
5
 
6
- # ecs/actions/ — async orchestration
6
+ # services/main-service/actions/ — async orchestration
7
7
 
8
8
  One action per file: a function taking the **whole database** as its first
9
9
  argument and pure `data/` args. Actions orchestrate anything *outside* a
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  paths:
3
- - '**/features/*/ecs/**/core-database/archetypes.ts'
3
+ - '**/features/*/services/main-service/**/core-database/archetypes.ts'
4
4
  ---
5
5
 
6
6
  # core-database/archetypes.ts — the feature's archetypes
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  paths:
3
- - '**/features/*/ecs/**/core-database/components.ts'
3
+ - '**/features/*/services/main-service/**/core-database/components.ts'
4
4
  ---
5
5
 
6
6
  # core-database/components.ts — the feature's components
@@ -28,7 +28,7 @@ export const components = Database.components({
28
28
  - A component name may differ from the type it stores (`position` of a `Vec3`,
29
29
  `mark` of a `PlayerMark`) — the field name describes the role, the schema the
30
30
  shape.
31
- - **Scope = which group it sits in** (see `ecs/index.md` for the four scopes and
31
+ - **Scope = which group it sits in** (see `services/main-service/index.md` for the four scopes and
32
32
  their flags). `document` is the common case; hover a scope key for its
33
33
  meaning. Never write `nonShared` / `nonPersistent` by hand — the group applies
34
34
  them.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  paths:
3
- - '**/features/*/ecs/**/computed/**/*.ts'
3
+ - '**/features/*/services/main-service/**/computed/**/*.ts'
4
4
  ---
5
5
 
6
6
  # database/computed/ — derived observable values
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  paths:
3
- - '**/features/*/ecs/**/conformance/**/*.ts'
3
+ - '**/features/*/services/main-service/**/conformance/**/*.ts'
4
4
  ---
5
5
 
6
- # ecs/conformance/ — spec↔implementation projection (test-only)
6
+ # services/main-service/conformance/ — spec↔implementation projection (test-only)
7
7
 
8
8
  The bridge that keeps the ecs implementation honest against the `data/` spec.
9
9
  **Test-only**: imported solely by `*.test.ts` and in no facet barrel, so it never
@@ -19,7 +19,7 @@ The property, per `{ before, args, after }` case:
19
19
 
20
20
  Conformance test-support splits by concern along the layer boundary:
21
21
 
22
- - **Store-side, here in `ecs/conformance/`:**
22
+ - **Store-side, here in `services/main-service/conformance/`:**
23
23
  - `from-state.ts` → `fromState(store: CoreDatabase.Store, state: State): void`
24
24
  seeds the store (clear tail→head → insert entities → set resources) to a `State`.
25
25
  - `to-state.ts` → `toState(store): State` reads the store back — each kind via
@@ -1,11 +1,13 @@
1
1
  ---
2
2
  paths:
3
- - '**/features/*/ecs/**/*.ts'
3
+ - '**/features/*/services/main-service/**/*.ts'
4
4
  ---
5
5
 
6
- # ecs/ — the Entity-Component-System layer
6
+ # services/main-service/ — the feature service (ECS implementation)
7
7
 
8
- Everything ECS-specific lives here: the schema that stores `data/` types as
8
+ `main-service/` is the feature's single entrypoint service (see `../index.md`),
9
+ implemented as a reactive Entity-Component-System — an implementation detail
10
+ behind the service. Everything ECS-specific lives here: the schema that stores `data/` types as
9
11
  entity state (`core-database/`), the derived and mutating logic over it
10
12
  (`indexes/`, `transactions/`, `computed/`), the database-bound service factories
11
13
  (`services/`), the async orchestrators (`actions/`), and the layered plugins
@@ -23,7 +25,7 @@ one `core-database/` folder: `core-database.ts` plus one file per facet the
23
25
  feature uses (all three facets are optional on `Database.Plugin.create`):
24
26
 
25
27
  ```
26
- ecs/core-database/
28
+ core-database/
27
29
  core-database.ts # Database.Plugin.create({ components?, resources?, archetypes? }) → CoreDatabase
28
30
  components.ts # export const components = Database.components({ … })
29
31
  resources.ts # export const resources = Database.resources({ … })
@@ -97,7 +99,7 @@ facet folder it adds. **Name each layer for the facet it adds — never for the
97
99
  feature or app.** A feature creates only the layers it uses:
98
100
 
99
101
  ```
100
- ecs/
102
+ main-service/
101
103
  core-database/ # the schema (above)
102
104
  index-database/ # extends core; indexes/
103
105
  transaction-database/ # extends index; transactions/
@@ -107,7 +109,7 @@ ecs/
107
109
  ```
108
110
 
109
111
  Each exports a namespace mirroring the plugin — the composed object is a
110
- `Database` (the `@adobe/data` term) even though the folder is `ecs/`:
112
+ `Database` (the `@adobe/data` term) even though the folder is `services/main-service/`:
111
113
 
112
114
  ```ts
113
115
  export type IndexDatabase = Database.Plugin.ToDatabase<typeof indexDatabasePlugin>;
@@ -120,12 +122,12 @@ export namespace IndexDatabase {
120
122
  ### The assembled database — `FeatureDatabase`
121
123
 
122
124
  *Which* layer is topmost varies with the facets a feature uses (computed /
123
- service / action / system). Consumers — `ui/`, the app entry, `ecs/conformance/`
125
+ service / action / system). Consumers — `ui/`, the app entry, `services/main-service/conformance/`
124
126
  — need the *whole* feature database but must not name that layer, or adding or
125
127
  dropping a layer rewrites them all. Alias it once:
126
128
 
127
129
  ```ts
128
- // ecs/feature-database.ts
130
+ // services/main-service/feature-database.ts
129
131
  export { SystemDatabase as FeatureDatabase } from "./system-database/system-database.js";
130
132
  ```
131
133
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  paths:
3
- - '**/features/*/ecs/**/indexes/**/*.ts'
3
+ - '**/features/*/services/main-service/**/indexes/**/*.ts'
4
4
  ---
5
5
 
6
6
  # database/indexes/ — ECS indexes
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  paths:
3
- - '**/features/*/ecs/**/core-database/resources.ts'
3
+ - '**/features/*/services/main-service/**/core-database/resources.ts'
4
4
  ---
5
5
 
6
6
  # core-database/resources.ts — the feature's resources
@@ -21,7 +21,7 @@ export const resources = Database.resources({
21
21
 
22
22
  - Give each resource a `default` — spread the data-type's schema and add one, or
23
23
  bind a `data/` / primitive schema that already carries a sensible default.
24
- - **Scope = which group it sits in** (see `ecs/index.md`). A per-device
24
+ - **Scope = which group it sits in** (see `services/main-service/index.md`). A per-device
25
25
  preference is `settings` (durable, `nonShared`); a synced-but-unsaved value is
26
26
  `presence`; a saved shared value is `document`.
27
27
  - Because there is only ever one instance, linear-memory packing buys nothing —
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  paths:
3
- - '**/features/*/ecs/**/services/**/*.ts'
3
+ - '**/features/*/services/main-service/**/services/**/*.ts'
4
4
  ---
5
5
 
6
6
  # database/services/ — database-bound service factories
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  paths:
3
- - '**/features/*/ecs/**/systems/**/*.ts'
3
+ - '**/features/*/services/main-service/**/systems/**/*.ts'
4
4
  - '**/systems/*.ts'
5
5
  ---
6
6
 
@@ -32,6 +32,8 @@ import { Database, scheduler } from "@adobe/data/ecs";
32
32
  import { Motion } from "../../data/motion/motion.js";
33
33
 
34
34
  const plugin = Database.Plugin.create({
35
+ // combine scheduler with the CURRENT TOP layer — ComputedDatabase here, but
36
+ // ActionDatabase / ServiceDatabase if the feature built those (systems come last).
35
37
  extends: Database.Plugin.combine(ComputedDatabase.plugin, scheduler),
36
38
  systems: {
37
39
  control: { create: (db) => () => { /* input → ship; db.transactions.fireBullet() */ } },
@@ -119,15 +121,17 @@ with no rAF and no rendering attached.
119
121
 
120
122
  ## Layer
121
123
 
122
- `system-database.ts` extends the previous ecs layer (usually `ComputedDatabase`),
123
- combined with `scheduler`, and declares the `systems` map **inline** (see above —
124
+ `system-database.ts` extends the feature's **current top** main-service layer (`ActionDatabase` /
125
+ `ServiceDatabase` / `ComputedDatabase` — whichever it built; systems come last in the pipeline, so
126
+ they must sit atop any service/action layers, not a hardcoded `ComputedDatabase`), combined with
127
+ `scheduler`, and declares the `systems` map **inline** (see above —
124
128
  this is the one facet not split one-per-file, because `create`'s `db` is only typed
125
129
  inline and standalone declarations break name inference). A `systems/` folder is
126
130
  optional: it holds extracted per-frame body helpers (`(db) => () => void`) only when
127
131
  an inline body grows too large — the schedule and registration still live inline in
128
132
  `system-database.ts`. The headless conformance test drives one frame via
129
133
  `db.system.order` / `db.system.functions` and compares to the `data/` `step` oracle,
130
- **reusing the feature projection** (`ecs/conformance.md`); it lives at
134
+ **reusing the feature projection** (`services/main-service/conformance.md`); it lives at
131
135
  `system-database/tick-loop.test.ts`. Test **selection/detection** logic (which
132
136
  entities collide, which pair resolves) separately, with seeded edge-case geometries
133
137
  — it's a system concern, not a transaction, and where subtle bugs hide.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  paths:
3
- - '**/features/*/ecs/**/transactions/**/*.ts'
3
+ - '**/features/*/services/main-service/**/transactions/**/*.ts'
4
4
  ---
5
5
 
6
6
  # database/transactions/ — atomic mutations
@@ -32,7 +32,7 @@ export const playMove = (t: CoreDatabase.Store, { index }: PlayMoveArgs) => {
32
32
  result — read the touched slice, call the `data/` transform, write the diff.
33
33
  - **Conform every transaction to its `data/` transform** in its sibling
34
34
  `*.test.ts`, via `expectConforms` over the spec's shared cases (see
35
- `ecs/conformance.md`): seed `fromState(before)`, dispatch, assert `toState ≡
35
+ `services/main-service/conformance.md`): seed `fromState(before)`, dispatch, assert `toState ≡
36
36
  after`, covering every branch and edge case. A transaction taking **entity
37
37
  ids** resolves them from the seeded store in the `apply` closure; one with no
38
38
  `data/` analogue (`setBounds`, `setInput`) gets a direct resource assertion.
@@ -41,5 +41,5 @@ export const playMove = (t: CoreDatabase.Store, { index }: PlayMoveArgs) => {
41
41
  transactions (`readShip`, `readBoard` — a `(t) => value` function) may live
42
42
  beside them in `transactions/`, but keep it **out of the barrel**, or it gets
43
43
  registered as a dispatchable transaction. (These are related helpers, so they
44
- belong here, not in a separate folder — `cohesion.md`'s peer-level caution
44
+ belong here, not in a separate folder — `global/cohesion.md`'s peer-level caution
45
45
  doesn't apply.)
@@ -32,7 +32,7 @@ Presentation files (`*-presentation.ts`), CSS files (`*.css.ts`), tests (`*.test
32
32
  A binding element is a thin wire between a service and a presentation. The class body contains:
33
33
 
34
34
  1. Optional static `styles` property definition
35
- 2. Zero or more `@property` declarations (whitelisted below).
35
+ 2. Zero or more `@property` declarations (allowed below).
36
36
  3. One `render()` method whose body is: one `useObservableValues(...)` call, another lifecycle hook call (in rare cases), a null-guard, and
37
37
  `return presentation.render({ ...values, ...callbacks })`.
38
38
 
@@ -40,7 +40,7 @@ No other members. No `@state`. No private handler fields. No lifecycle methods (
40
40
  `disconnectedCallback`) except on app-entrypoint classes where the lifecycle concern is app-boot shaped but cannot be expressed as a hook
41
41
  (see `.claude/rules/hooks.md` for hook-first lifecycle).
42
42
 
43
- ## `@property` whitelist
43
+ ## `@property` allowlist
44
44
 
45
45
  The allowed set depends on **class role**:
46
46
 
@@ -5,7 +5,7 @@ paths:
5
5
 
6
6
  # ui/ — user interface
7
7
 
8
- The top layer: UI that binds the `ecs/` database to what the user sees. It
8
+ The top layer: UI that binds the `services/main-service/` database to what the user sees. It
9
9
  owns no business logic — it subscribes to state, hands it to a pure
10
10
  presentation, and wires actions back to transactions.
11
11
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adobe-data-ai",
3
- "version": "0.9.89",
3
+ "version": "0.9.91",
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
@@ -2,7 +2,7 @@
2
2
 
3
3
  AI architecture skills + rules for building applications with
4
4
  [`@adobe/data`](https://www.npmjs.com/package/@adobe/data) — a layered,
5
- spec-first feature structure (`data → ecs → ui`) kept honest by conformance
5
+ spec-first feature structure (`data → services → ui`) kept honest by conformance
6
6
  tests. Versioned in lockstep with the library: `@adobe/data-ai@x.y.z` targets
7
7
  `@adobe/data@x.y.z`.
8
8
 
package/bin/cli.mjs CHANGED
@@ -50,8 +50,8 @@ function notice(extra) {
50
50
 
51
51
  The files in this folder are installed and managed by the \`${PKG_NAME}\`
52
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.
53
+ \`npx ${PKG_NAME}@${VERSION} install\`, so any local edit here is silently discarded on
54
+ the next reinstall or version upgrade.
55
55
 
56
56
  To change them, edit upstream in the \`${PKG_NAME}\` package and publish a new
57
57
  version, then reinstall — do not modify these files in place.
@@ -66,10 +66,21 @@ function writeMeta(bundleDir, noticeBody, extraMeta) {
66
66
  );
67
67
  }
68
68
 
69
+ // Skills that author/evolve the bundle itself (the self-improvement loop and its
70
+ // rule review). They mutate or critique the managed files, so they belong only to
71
+ // the source repo — never a consumer install, where those files are read-only
72
+ // managed copies. Both also carry `disable-model-invocation: true`.
73
+ const MAINTAINER_ONLY = new Set(["meta-build", "review"]);
74
+
69
75
  function discoverSkills() {
70
76
  if (!existsSync(skillsSrc)) return [];
71
77
  return readdirSync(skillsSrc, { withFileTypes: true })
72
- .filter((d) => d.isDirectory() && existsSync(join(skillsSrc, d.name, "SKILL.md")))
78
+ .filter(
79
+ (d) =>
80
+ d.isDirectory() &&
81
+ !MAINTAINER_ONLY.has(d.name) &&
82
+ existsSync(join(skillsSrc, d.name, "SKILL.md")),
83
+ )
73
84
  .map((d) => d.name)
74
85
  .sort();
75
86
  }
@@ -111,6 +122,41 @@ function installRules(base) {
111
122
  return bundleDir;
112
123
  }
113
124
 
125
+ // A single managed rule (namespaced by its `adobe-data-ai-` filename prefix) telling
126
+ // an agent to (re)install the bundle when the skills are absent — pinned to THIS
127
+ // reviewed version, never `@latest`, so a drifted or compromised release cannot execute
128
+ // during install. Rewritten with the matching version on every install. It sits beside
129
+ // (not inside) the wiped bundle dir, so it survives and is simply overwritten.
130
+ function installBootstrap(base) {
131
+ const file = join(base, ".claude", "rules", `${BUNDLE}-bootstrap.md`);
132
+ mkdirSync(dirname(file), { recursive: true });
133
+ writeFileSync(
134
+ file,
135
+ `---
136
+ paths:
137
+ - '**/features/*/data/**/*.ts'
138
+ - '**/features/*/services/**/*.ts'
139
+ - '**/features/*/ui/**/*.ts'
140
+ ---
141
+
142
+ # ${PKG_NAME} skills — ensure installed
143
+
144
+ Before using an \`@adobe/data\` build workflow, confirm the skills are present: look for
145
+ a skill named \`build-feature\` (or \`build-application\`). If it is missing, install the
146
+ pinned, reviewed bundle, then re-check:
147
+
148
+ \`\`\`sh
149
+ npx ${PKG_NAME}@${VERSION} install
150
+ \`\`\`
151
+
152
+ Pin the version to the reviewed bundle (never \`@latest\`) so a compromised or drifted
153
+ release cannot execute during install. This file is regenerated with the matching
154
+ version on every install. Package: <https://www.npmjs.com/package/${PKG_NAME}>
155
+ `,
156
+ );
157
+ return file;
158
+ }
159
+
114
160
  function parseArgs(argv) {
115
161
  const positional = [];
116
162
  const flags = new Set();
@@ -176,11 +222,13 @@ function main() {
176
222
  const base = flags.has("global") ? homedir() : dir ? resolve(dir) : process.cwd();
177
223
  const skillsDir = installSkills(base, skills);
178
224
  const rulesDir = installRules(base);
225
+ const bootstrapFile = installBootstrap(base);
179
226
  const ruleCount = countRules(rulesSrc);
180
227
 
181
228
  process.stdout.write(`Installed ${PKG_NAME} v${VERSION}\n`);
182
229
  process.stdout.write(` ${skills.length} skills → ${skillsDir}\n`);
183
230
  process.stdout.write(` ${ruleCount} rules → ${rulesDir}\n`);
231
+ process.stdout.write(` bootstrap → ${bootstrapFile}\n`);
184
232
  }
185
233
 
186
234
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/data-ai",
3
- "version": "0.9.89",
3
+ "version": "0.9.91",
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,
@@ -29,18 +29,17 @@
29
29
  "skills"
30
30
  ],
31
31
  "peerDependencies": {
32
- "@adobe/data": "0.9.89"
32
+ "@adobe/data": "0.9.91"
33
33
  },
34
34
  "devDependencies": {
35
35
  "typescript": "^5.8.3",
36
36
  "vitest": "^1.6.0",
37
- "@adobe/data": "0.9.89"
37
+ "@adobe/data": "0.9.91"
38
38
  },
39
39
  "license": "MIT",
40
40
  "scripts": {
41
41
  "build": "cp ../../LICENSE .",
42
42
  "typecheck": "true",
43
- "test": "vitest --run --passWithNoTests",
44
- "publish-public": "pnpm build && pnpm publish --no-git-checks --access public"
43
+ "test": "vitest --run --passWithNoTests"
45
44
  }
46
45
  }
@@ -1,16 +1,16 @@
1
1
  ---
2
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 or side effects outside of the main store.
3
+ description: Build a feature's action-database — async orchestration over services and transactions. If the feature has async flows or side effects outside of the main store.
4
4
  input: feature
5
5
  output: feature
6
6
  ---
7
7
 
8
8
  Skip if this feature doesn't contain or require actions.
9
9
 
10
- Create `ecs/action-database/`: `action-database.ts` (extends `ServiceDatabase`, adds `actions`
10
+ Create `services/main-service/action-database/`: `action-database.ts` (extends `ServiceDatabase`, adds `actions`
11
11
  from `./actions/index.js`) plus an `actions/` folder — one async orchestrator per file. An action
12
12
  takes `db: ServiceDatabase`, awaits `services/` ports, then commits **exactly one** transaction.
13
13
 
14
- The top ecs layer; comes after `service-database`.
14
+ The top main-service layer; comes after `service-database`.
15
15
 
16
- The how is in the auto-loading `features/ecs/actions.md` rule.
16
+ The how is in the auto-loading `features/services/main-service/actions.md` rule.
@@ -10,6 +10,6 @@ output: app
10
10
  - The base reaches a peer only through a lazy element wrapper (dynamic import), so peers
11
11
  load on demand.
12
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.
13
+ feature's assembled database — see `features/services/main-service/index.md`) and mounts the root UI.
14
14
 
15
15
  See `features/index.md` (one-app-many-features) for the wiring rules.
@@ -1,16 +1,16 @@
1
1
  ---
2
2
  name: build-computed
3
- description: Build a feature's ecs computed-database — derived observable values.
3
+ description: Build a feature's computed-database — derived observable values.
4
4
  input: feature
5
5
  output: feature
6
6
  ---
7
7
 
8
8
  Skip if this feature doesn't contain or require computed values.
9
9
 
10
- Create `ecs/computed-database/`: `computed-database.ts` (extends the previous layer, adds
10
+ Create `services/main-service/computed-database/`: `computed-database.ts` (extends the previous layer, adds
11
11
  `computed` from `./computed/index.js`) plus a `computed/` folder — one `cached` derived value
12
12
  per file + barrel. Derivation logic lives in `data/`; a computed only wires a db observable to it.
13
13
 
14
14
  Comes after `transaction-database`.
15
15
 
16
- The how is in the auto-loading `features/ecs/computed.md` rule.
16
+ The how is in the auto-loading `features/services/main-service/computed.md` rule.
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: build-core-database
3
- description: Build a feature's ecs schema — the core-database (components, resources, archetypes). The first ecs layer.
3
+ description: Build a feature's schema — the core-database (components, resources, archetypes). The first main-service layer.
4
4
  input: feature
5
5
  output: feature
6
6
  ---
7
7
 
8
- Create `ecs/core-database/` — `core-database.ts` plus one single-export file per facet
8
+ Create `services/main-service/core-database/` — `core-database.ts` plus one single-export file per facet
9
9
  the feature actually uses (`components`, `resources`, `archetypes` are each optional on
10
10
  `Database.Plugin.create`). Create only the facet files you need; omit the rest rather than
11
11
  shipping empty `Database.components({})` boilerplate. A feature with **no entities** (a
@@ -20,5 +20,5 @@ The schema root; comes after `data/` (and `services/`). Bind each schema from it
20
20
  type — don't author shapes here. Components use JSON schemas; resources use the
21
21
  `{ default }` convention (a schemaless aggregate binds via `{ default: State.create() }`).
22
22
 
23
- The how is in the auto-loading `features/ecs/index.md` + `components.md` / `resources.md` /
23
+ The how is in the auto-loading `features/services/main-service/index.md` + `components.md` / `resources.md` /
24
24
  `archetypes.md` rules.
@@ -19,4 +19,4 @@ The schema is the single source of truth; the type derives from it (`Schema.ToTy
19
19
  Helpers are pure and unit-tested. Run this first — every other layer imports `data/`.
20
20
 
21
21
  The how is in the auto-loading rules: `features/data/index.md`, `features/data/state.md`, and
22
- `namespace.md`.
22
+ `global/namespace.md`.
@@ -16,6 +16,6 @@ transactions = moves/spawns, computed = score/status/winner, ui = view + input.
16
16
  - **Real-time** adds the `build-systems` phase: a per-frame tick loop (movement,
17
17
  collision, lifetime) driven by the scheduler, over many entities in distinct
18
18
  archetypes. Systems must stay O(1) per touched entity — never project the whole
19
- `State` into/out of the store each frame (see `features/ecs/systems.md`).
19
+ `State` into/out of the store each frame (see `features/services/main-service/systems.md`).
20
20
  This is where components, archetypes, indexes, and systems all carry real
21
21
  weight.
@@ -1,16 +1,16 @@
1
1
  ---
2
2
  name: build-indexes
3
- description: Build a feature's ecs index-database — component/archetype indexes for O(1) lookup. As needed.
3
+ description: Build a feature's index-database — component/archetype indexes for O(1) lookup. As needed.
4
4
  input: feature
5
5
  output: feature
6
6
  ---
7
7
 
8
8
  Skip if this feature doesn't contain or require indexes.
9
9
 
10
- Create `ecs/index-database/`: `index-database.ts` (extends `CoreDatabase`, adds the `indexes`
10
+ Create `services/main-service/index-database/`: `index-database.ts` (extends `CoreDatabase`, adds the `indexes`
11
11
  facet from `./indexes/index.js`) plus an `indexes/` folder — one index per file + an `index.ts`
12
12
  barrel.
13
13
 
14
14
  Only if the feature needs indexed lookups. Comes after `core-database`.
15
15
 
16
- The how is in the auto-loading `features/ecs/indexes.md` rule.
16
+ The how is in the auto-loading `features/services/main-service/indexes.md` rule.
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: build-service-database
3
- description: Build a feature's ecs service-database — db-bound service factories. If the feature exposes services.
3
+ description: Build a feature's service-database — db-bound service factories. If the feature exposes services.
4
4
  input: feature
5
5
  output: feature
6
6
  ---
7
7
 
8
- Create `ecs/service-database/`: `service-database.ts` (extends the previous layer, registers the
8
+ Create `services/main-service/service-database/`: `service-database.ts` (extends the previous layer, registers the
9
9
  `services` facet). Two forms:
10
10
 
11
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
@@ -13,4 +13,4 @@ Create `ecs/service-database/`: `service-database.ts` (extends the previous laye
13
13
 
14
14
  Comes after `computed-database`.
15
15
 
16
- The how is in the auto-loading `features/ecs/services.md` rule.
16
+ The how is in the auto-loading `features/services/main-service/services.md` rule.
@@ -11,6 +11,6 @@ Create the feature's `services/` layer: one `<name>-service/` namespace folder p
11
11
  contract — an `interface` (validated with `AsyncDataService.IsValid`), async-only members,
12
12
  and `create*` factories.
13
13
 
14
- Only if the feature talks to the outside world. Comes after `data/`, before `ecs/`.
14
+ Only if the feature talks to the outside world. Comes after `data/`, before `services/main-service/`.
15
15
 
16
- The how is in the auto-loading `features/services/index.md` rule (and `namespace.md`).
16
+ The how is in the auto-loading `features/services/index.md` rule (and `global/namespace.md`).
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: build-systems
3
- description: Build a feature's ecs system-database — the real-time tick loop (systems the scheduler runs each frame). For real-time features only.
3
+ description: Build a feature's system-database — the real-time tick loop (systems the scheduler runs each frame). For real-time features only.
4
4
  input: feature
5
5
  output: feature
6
6
  ---
@@ -8,9 +8,12 @@ output: feature
8
8
  Skip if this feature doesn't contain or require systems.
9
9
  Most games that use a canvas will use systems but most applications will not.
10
10
 
11
- Create `ecs/system-database/system-database.ts`: `Database.Plugin.create({ extends:
12
- Database.Plugin.combine(ComputedDatabase.plugin, scheduler), systems })` where the `systems`
13
- map is declared **inline** (see `features/ecs/systems.md` — inline is required for `db` to be
11
+ Create `services/main-service/system-database/system-database.ts`: `Database.Plugin.create({ extends:
12
+ Database.Plugin.combine(<currentTop>.plugin, scheduler), systems })` — combine `scheduler` with the
13
+ feature's **current top** main-service layer (`ActionDatabase` / `ServiceDatabase` / `ComputedDatabase`,
14
+ whichever it built), never a hardcoded `ComputedDatabase`, so systems *and* any services/actions
15
+ compose into the one `FeatureDatabase`. The `systems`
16
+ map is declared **inline** (see `features/services/main-service/systems.md` — inline is required for `db` to be
14
17
  typed and for system-name inference; a `systems/` folder is optional, only for extracted
15
18
  per-frame body helpers).
16
19
 
@@ -21,4 +24,4 @@ per-frame body helpers).
21
24
  combining `scheduler` (rAF), gated by the `schedulerState` resource.
22
25
 
23
26
  **Only for real-time features** (games, sims) — turn-based features skip this phase entirely.
24
- Comes after `build-computed`. The how is in the auto-loading `features/ecs/systems.md` rule.
27
+ Comes after `build-computed`. The how is in the auto-loading `features/services/main-service/systems.md` rule.
@@ -1,15 +1,16 @@
1
1
  ---
2
2
  name: build-transactions
3
- description: Build a feature's ecs transaction-database — atomic mutations over the store.
3
+ description: Build a feature's transaction-database — atomic mutations over the store.
4
4
  input: feature
5
5
  output: feature
6
6
  ---
7
7
 
8
- Create `ecs/transaction-database/`: `transaction-database.ts` (extends `IndexDatabase`, adds
8
+ Create `services/main-service/transaction-database/`: `transaction-database.ts` (extends the
9
+ preceding layer — `IndexDatabase` if the feature built indexes, else `CoreDatabase` — adds
9
10
  `transactions` from `./transactions/index.js`) plus a `transactions/` folder — one mutation per
10
11
  file + barrel. Type the store param `CoreDatabase.Store` (entities/resources/archetypes) or
11
12
  `IndexDatabase.Store` (reads an index).
12
13
 
13
14
  Comes after `index-database` (or `core-database` if no indexes).
14
15
 
15
- The how is in the auto-loading `features/ecs/transactions.md` rule.
16
+ The how is in the auto-loading `features/services/main-service/transactions.md` rule.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: build-ui
3
- description: Build a feature's ui/ layer — presentation bound to the ecs database. The final, top layer.
3
+ description: Build a feature's ui/ layer — presentation bound to the main-service database. The final, top layer.
4
4
  input: feature
5
5
  output: feature
6
6
  ---
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: meta-build
3
+ disable-model-invocation: true
3
4
  description: Iteratively build an application or game phase-by-phase in clean subagents, reviewing each phase and refining the build-* skills / rules until each is optimal, then summarizing.
4
5
  input: a prompt describing the application or game to build
5
6
  options:
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: review
3
+ disable-model-invocation: true
3
4
  description: Review built feature/application output against the @adobe/data feature rules; report whether it is optimal and where any fix belongs. Read-only.
4
5
  input: a path to built output (a layer, a feature, or a whole app)
5
6
  output: a review — OPTIMAL, or a list of issues each tagged code | skill | rule
File without changes