mythik 0.1.5 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -36
- package/dist/actions/dispatcher.d.ts +2 -0
- package/dist/actions/dispatcher.d.ts.map +1 -1
- package/dist/actions/dispatcher.js +11 -2
- package/dist/actions/dispatcher.js.map +1 -1
- package/dist/actions/transaction-engine.d.ts +10 -0
- package/dist/actions/transaction-engine.d.ts.map +1 -1
- package/dist/actions/transaction-engine.js +13 -1
- package/dist/actions/transaction-engine.js.map +1 -1
- package/dist/agent-context/inventory.d.ts +62 -0
- package/dist/agent-context/inventory.d.ts.map +1 -0
- package/dist/agent-context/inventory.js +248 -0
- package/dist/agent-context/inventory.js.map +1 -0
- package/dist/contract/extractor.js +3 -0
- package/dist/contract/extractor.js.map +1 -1
- package/dist/data/data-sources.d.ts +16 -0
- package/dist/data/data-sources.d.ts.map +1 -1
- package/dist/data/data-sources.js +16 -1
- package/dist/data/data-sources.js.map +1 -1
- package/dist/editor-session/engine.d.ts +1 -0
- package/dist/editor-session/engine.d.ts.map +1 -1
- package/dist/editor-session/engine.js +5 -4
- package/dist/editor-session/engine.js.map +1 -1
- package/dist/fetch/framework-fetch.d.ts +1 -0
- package/dist/fetch/framework-fetch.d.ts.map +1 -1
- package/dist/fetch/framework-fetch.js +34 -4
- package/dist/fetch/framework-fetch.js.map +1 -1
- package/dist/fetch/interceptors/auth.d.ts +2 -0
- package/dist/fetch/interceptors/auth.d.ts.map +1 -1
- package/dist/fetch/interceptors/auth.js +31 -2
- package/dist/fetch/interceptors/auth.js.map +1 -1
- package/dist/fetch/types.d.ts +4 -0
- package/dist/fetch/types.d.ts.map +1 -1
- package/dist/index.d.ts +12 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/renderer/engine.d.ts.map +1 -1
- package/dist/renderer/engine.js +29 -4
- package/dist/renderer/engine.js.map +1 -1
- package/dist/renderer/prop-schemas.d.ts +5 -0
- package/dist/renderer/prop-schemas.d.ts.map +1 -1
- package/dist/renderer/prop-schemas.js +11 -2
- package/dist/renderer/prop-schemas.js.map +1 -1
- package/dist/reveal/context.d.ts +22 -0
- package/dist/reveal/context.d.ts.map +1 -0
- package/dist/reveal/context.js +159 -0
- package/dist/reveal/context.js.map +1 -0
- package/dist/reveal/index.d.ts +7 -0
- package/dist/reveal/index.d.ts.map +1 -0
- package/dist/reveal/index.js +7 -0
- package/dist/reveal/index.js.map +1 -0
- package/dist/reveal/protocol.d.ts +28 -0
- package/dist/reveal/protocol.d.ts.map +1 -0
- package/dist/reveal/protocol.js +2 -0
- package/dist/reveal/protocol.js.map +1 -0
- package/dist/reveal/recorder.d.ts +20 -0
- package/dist/reveal/recorder.d.ts.map +1 -0
- package/dist/reveal/recorder.js +31 -0
- package/dist/reveal/recorder.js.map +1 -0
- package/dist/reveal/redaction.d.ts +12 -0
- package/dist/reveal/redaction.d.ts.map +1 -0
- package/dist/reveal/redaction.js +85 -0
- package/dist/reveal/redaction.js.map +1 -0
- package/dist/reveal/truncation.d.ts +4 -0
- package/dist/reveal/truncation.d.ts.map +1 -0
- package/dist/reveal/truncation.js +48 -0
- package/dist/reveal/truncation.js.map +1 -0
- package/dist/reveal/types.d.ts +104 -0
- package/dist/reveal/types.d.ts.map +1 -0
- package/dist/reveal/types.js +2 -0
- package/dist/reveal/types.js.map +1 -0
- package/dist/runtime/mount-spec-runtime.d.ts +7 -0
- package/dist/runtime/mount-spec-runtime.d.ts.map +1 -1
- package/dist/runtime/mount-spec-runtime.js +5 -1
- package/dist/runtime/mount-spec-runtime.js.map +1 -1
- package/dist/security/spec-validator.d.ts.map +1 -1
- package/dist/security/spec-validator.js +61 -0
- package/dist/security/spec-validator.js.map +1 -1
- package/dist/spec-stores/file.js +1 -1
- package/dist/spec-stores/file.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/consumer/README.md +11 -0
- package/docs/consumer/WHERE-TO-LOOK.md +1 -1
- package/docs/consumer/ai-context-patterns.md +42 -7
- package/docs/consumer/ai-context-primitives.md +25 -2
- package/docs/consumer/ai-context-runtime-semantics.md +32 -19
- package/docs/consumer/ai-context.md +106 -20
- package/docs/consumer/reference-doc.md +170 -35
- package/docs/llms.txt +6 -1
- package/docs/wiki/compiled/README.md +13 -11
- package/docs/wiki/compiled/_gaps.md +1 -1
- package/docs/wiki/compiled/_index.md +11 -7
- package/docs/wiki/compiled/_inventory.md +22 -14
- package/docs/wiki/compiled/_lint.md +21 -17
- package/docs/wiki/compiled/antipattern-store-save-bypass.md +13 -8
- package/docs/wiki/compiled/cli-agent.md +70 -0
- package/docs/wiki/compiled/cli-existing-spec-edit-loop.md +9 -8
- package/docs/wiki/compiled/cli-overview.md +12 -7
- package/docs/wiki/compiled/cli-patch.md +14 -11
- package/docs/wiki/compiled/cli-programmatic-api.md +17 -7
- package/docs/wiki/compiled/cli-push.md +36 -24
- package/docs/wiki/compiled/cli-reveal.md +64 -0
- package/docs/wiki/compiled/cli-toon.md +9 -9
- package/docs/wiki/compiled/cli-versioning-author.md +19 -15
- package/docs/wiki/compiled/concept-agent-context-protocol.md +76 -0
- package/docs/wiki/compiled/concept-component-variants.md +39 -10
- package/docs/wiki/compiled/concept-mythik-reveal.md +63 -0
- package/docs/wiki/compiled/concept-package-layout.md +7 -6
- package/docs/wiki/compiled/concept-public-package-names.md +9 -5
- package/docs/wiki/compiled/concept-shape-animations.md +4 -2
- package/docs/wiki/compiled/concept-spec-store-interface.md +7 -4
- package/docs/wiki/compiled/concept-spec-store-layering.md +5 -5
- package/docs/wiki/compiled/concept-templates-vs-variants.md +77 -13
- package/docs/wiki/compiled/concept-versioned-store.md +8 -5
- package/docs/wiki/compiled/pattern-git-vs-db-versioning.md +8 -6
- package/docs/wiki/compiled/pattern-push-vs-patch.md +13 -12
- package/docs/wiki/compiled/pattern-reusable-components.md +42 -12
- package/package.json +1 -1
|
@@ -180,7 +180,7 @@ Parametrize via `$prop`. Use `$children` in template's `children` array to slot
|
|
|
180
180
|
|
|
181
181
|
### When to use `tokens.components.{type}.{variantName}`
|
|
182
182
|
|
|
183
|
-
Define a reusable style set for a PRIMITIVE (button, input, card) that merges into every element declaring `variant: "name"`. Use for STYLE-ONLY reuse (same type, different visual variant).
|
|
183
|
+
Define a reusable style set for a PRIMITIVE (button, input, card, table root, touchable chip shell) that merges into every element declaring `props.variant: "name"`. Use for STYLE-ONLY reuse (same type, different visual variant).
|
|
184
184
|
|
|
185
185
|
**Defining a variant:**
|
|
186
186
|
```json
|
|
@@ -204,10 +204,44 @@ Define a reusable style set for a PRIMITIVE (button, input, card) that merges in
|
|
|
204
204
|
}
|
|
205
205
|
```
|
|
206
206
|
|
|
207
|
-
**Using in any spec:**
|
|
208
|
-
```json
|
|
209
|
-
{ "type": "button", "props": { "variant": "ctaPulse", "label": "..." } }
|
|
210
|
-
```
|
|
207
|
+
**Using in any spec:**
|
|
208
|
+
```json
|
|
209
|
+
{ "type": "button", "props": { "variant": "ctaPulse", "label": "..." } }
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Variants intentionally cover visual slots only: `style`, `hover`, `active`, `focus`, `transition`, and `animations`. They do not carry arbitrary primitive props. If the repeated pattern includes table `headerStyle`/`rowStyle`, `columns`, `onRowClick`, child composition, or action bindings, use a template or custom element instead.
|
|
213
|
+
|
|
214
|
+
**Data table chrome pattern:** put the panel shell in a `box` variant, then wrap the table in an AppSpec template so the shared `headerStyle`/`rowStyle` lives once.
|
|
215
|
+
|
|
216
|
+
```json
|
|
217
|
+
{
|
|
218
|
+
"tokens": {
|
|
219
|
+
"components": {
|
|
220
|
+
"box": {
|
|
221
|
+
"tableCard": { "style": { "padding": 0, "overflow": "hidden" } }
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
"templates": {
|
|
226
|
+
"ops-table": {
|
|
227
|
+
"type": "table",
|
|
228
|
+
"defaults": {
|
|
229
|
+
"headerStyle": { "minHeight": 44, "background": "#F8FAFC" },
|
|
230
|
+
"rowStyle": { "base": { "minHeight": 43 }, "hover": { "backgroundColor": "#F8FAFC" } }
|
|
231
|
+
},
|
|
232
|
+
"props": {
|
|
233
|
+
"data": { "$prop": "data" },
|
|
234
|
+
"columns": { "$prop": "columns" },
|
|
235
|
+
"onRowClick": { "$prop": "onRowClick" },
|
|
236
|
+
"headerStyle": { "$prop": "headerStyle" },
|
|
237
|
+
"rowStyle": { "$prop": "rowStyle" }
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Filter chip pattern:** for chips composed from `touchable` + `text`, define static shell/label variants, then keep active-state `$state`/`$item` color expressions on the actual chip elements. Variants do not evaluate `$state`/`$item`; templates/custom elements are the heavier option when the composition itself should be reusable.
|
|
211
245
|
|
|
212
246
|
### Rule: don't duplicate style blocks across specs
|
|
213
247
|
|
|
@@ -235,8 +269,9 @@ If the same rich style object appears in 2+ specs (or 2+ places in same spec), e
|
|
|
235
269
|
|
|
236
270
|
| Situation | Use |
|
|
237
271
|
|---|---|
|
|
238
|
-
| Same primitive type, different style set | `tokens.components.{type}.{variant}` |
|
|
239
|
-
|
|
|
272
|
+
| Same primitive type, different style set | `tokens.components.{type}.{variant}` |
|
|
273
|
+
| Primitive style plus repeated primitive props (e.g. table `headerStyle`/`rowStyle`) | `appSpec.templates` |
|
|
274
|
+
| Composite (custom type wrapping primitive + children slot) | `appSpec.templates` or Layer 3 custom element |
|
|
240
275
|
| Style varies by state (hover/active/focus) | Variants (built-in state slots) |
|
|
241
276
|
| Parametrized via props + children | Templates (with `$prop` + `$children`) |
|
|
242
277
|
|
|
@@ -41,6 +41,8 @@ Container element. Props: `className`, `surface`.
|
|
|
41
41
|
| `variant` | string | — | `heading` (h2), `body` (p), `caption` (span), `label` (label), `mono` (code) |
|
|
42
42
|
| `className` | string | — | CSS class |
|
|
43
43
|
|
|
44
|
+
**Events:** `on.press` is supported for inline interactive text. The renderer supplies button semantics and keyboard activation on web and `accessibilityRole="button"` on React Native. Use `button` or `touchable` for primary actions and larger tap targets.
|
|
45
|
+
|
|
44
46
|
### image
|
|
45
47
|
|
|
46
48
|
| Prop | Type | Default | Description |
|
|
@@ -61,7 +63,7 @@ Container element. Props: `className`, `surface`.
|
|
|
61
63
|
|
|
62
64
|
Names are kebab-case, library-agnostic.
|
|
63
65
|
|
|
64
|
-
**Icon renderer contract:** Mythik does not bundle an icon pack. The built-in `icon` primitive
|
|
66
|
+
**Icon renderer contract:** Mythik does not bundle an icon pack. Register icons once with `plugins.setIconRenderer(Component)`. The built-in `icon` primitive, table action icons, toast icons, and React Native icon consumers use that same registration. The built-in primitive keeps identity behavior (container, default weight) and calls your renderer with `{ name, size, weight, color, style }`. Use `overridePrimitive('icon')` only for full primitive replacement.
|
|
65
67
|
|
|
66
68
|
```tsx
|
|
67
69
|
import { MythikApp } from 'mythik-react';
|
|
@@ -102,7 +104,7 @@ function LucideIcon({ name, size, color, style }) {
|
|
|
102
104
|
|
|
103
105
|
**Troubleshooting:** if you see the placeholder circle, the renderer was not present in resolved tokens when the app applied plugins. Verify `onPlugins` calls `setIconRenderer`, verify the consumer is installed from a tarball/package that includes the `applyPlugins()` icon renderer fix, and avoid using source aliases when validating published-package behavior.
|
|
104
106
|
|
|
105
|
-
**
|
|
107
|
+
**Full primitive replacement:** `plugins.overridePrimitive('icon', ...)` is still supported, but it replaces the whole primitive and bypasses the built-in identity wrapper. The renderer function must return a Mythik `RenderNode`, not JSX:
|
|
106
108
|
|
|
107
109
|
```ts
|
|
108
110
|
plugins.overridePrimitive('icon', (props, children) => ({
|
|
@@ -120,8 +122,25 @@ plugins.overridePrimitive('icon', (props, children) => ({
|
|
|
120
122
|
| `gap` | number | — | Space between children (px) |
|
|
121
123
|
| `align` | string | — | Cross-axis: `start`, `center`, `end`, `stretch` |
|
|
122
124
|
| `justify` | string | — | Main-axis: `start`, `center`, `end`, `between`, `around` |
|
|
125
|
+
| `wrap` | boolean | `false` | Allow horizontal rows to wrap |
|
|
123
126
|
| `className` | string | — | CSS class |
|
|
124
127
|
|
|
128
|
+
`repeat.layout` lets a repeated container render its item rows horizontally without changing the child primitive:
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"type": "stack",
|
|
133
|
+
"repeat": {
|
|
134
|
+
"source": { "$state": "/filters" },
|
|
135
|
+
"key": "id",
|
|
136
|
+
"layout": { "direction": "horizontal", "gap": 8, "wrap": true }
|
|
137
|
+
},
|
|
138
|
+
"children": ["filter-chip"]
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Grouped repeats keep group headers/footers vertical and apply `repeat.layout` only to each group's item row.
|
|
143
|
+
|
|
125
144
|
### grid
|
|
126
145
|
|
|
127
146
|
| Prop | Type | Default | Description |
|
|
@@ -197,6 +216,8 @@ Props: `size` (px), `direction` (`vertical`/`horizontal`). Renders empty space.
|
|
|
197
216
|
| `options` | array | — | Strings or `[{ label, value }]` objects |
|
|
198
217
|
| `placeholder` | string | — | Placeholder text |
|
|
199
218
|
| `label` | string/expression | — | Field label |
|
|
219
|
+
| `labelKey` | string | — | Label field for catalog-shaped options |
|
|
220
|
+
| `valueKey` | string | — | Value field for catalog-shaped options |
|
|
200
221
|
| `disabled` | boolean/expression | `false` | Disable |
|
|
201
222
|
| `required` | boolean | `false` | Visual indicator |
|
|
202
223
|
|
|
@@ -209,6 +230,8 @@ Options formats:
|
|
|
209
230
|
"options": { "$state": "/cat/services/data" }, "labelKey": "name", "valueKey": "id"
|
|
210
231
|
```
|
|
211
232
|
|
|
233
|
+
`select` matches the current value against options by normalized scalar key. DB integer IDs and string option values match for display. `0` is a valid selected value. Null/undefined show the placeholder. Existing `onChange` output remains string-compatible.
|
|
234
|
+
|
|
212
235
|
`labelKey` defaults to `"label"` and `valueKey` defaults to `"value"`. Use them for catalog rows such as `{ "id": 1, "name": "Cambio de aceite" }`. Values are emitted as strings from `on.change`. Malformed object options render as disabled diagnostics instead of blank clickable rows.
|
|
213
236
|
|
|
214
237
|
### checkbox
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
1. 🔴 [`/ui/selectedRow` magic path (§2.1)](#21-uiselectedrow--blocker-1)
|
|
15
15
|
2. 🔴 [CRUD 1-endpoint 3-route auto-generation (§3.1)](#31-crud--one-endpoint-three-routes--blocker-3)
|
|
16
16
|
3. 🟢 [dataSources + derive lifecycle (§5.2 + §5.3)](#52-datasources-lifecycle) — SHIPPED v0.1.0 Item E
|
|
17
|
-
4. 🟢 [authDomains
|
|
17
|
+
4. 🟢 [`apiBaseUrl` + `authDomains` auth target matching (§4.1)](#41-apibaseurl--authdomains--auth-target-matching)
|
|
18
18
|
|
|
19
19
|
These five behaviors caused the most source-reading in the 2026-04 consumer-simulation experiment. If you read only one section of this doc, read these.
|
|
20
20
|
|
|
@@ -612,26 +612,35 @@ Implementation: `packages/server/src/server.ts` (search `buildScopeWhereClause`
|
|
|
612
612
|
|
|
613
613
|
## 4. Matcher Semantics
|
|
614
614
|
|
|
615
|
-
### 4.1 `authDomains` —
|
|
615
|
+
### 4.1 `apiBaseUrl` + `authDomains` — auth target matching
|
|
616
616
|
|
|
617
|
-
**Contract:** auth
|
|
617
|
+
**Contract:** framework-owned runtime fetches resolve their URL before URL guards, auth interceptors, and fetch execution. When `MythikApp` receives `apiBaseUrl`, relative runtime URLs such as `/api/orders` resolve against that base. With web auth enabled, if `authDomains` is omitted or empty, the exact origin of `apiBaseUrl` (`protocol + host + port`) becomes the default effective auth target for framework-owned requests.
|
|
618
618
|
|
|
619
|
-
**
|
|
619
|
+
**Default `apiBaseUrl` auth rule:**
|
|
620
|
+
|
|
621
|
+
| Host config | Request URL in spec | Effective URL | Bearer token? |
|
|
622
|
+
|---|---|---|---|
|
|
623
|
+
| `apiBaseUrl: "http://localhost:3010"` | `/api/orders` | `http://localhost:3010/api/orders` | yes |
|
|
624
|
+
| `apiBaseUrl: "http://localhost:3010"` | `http://localhost:3010/api/orders` | unchanged | yes |
|
|
625
|
+
| `apiBaseUrl: "http://localhost:3010"` | `http://localhost:5173/api/orders` | unchanged | no |
|
|
626
|
+
| `apiBaseUrl: "http://localhost:3010"` | `https://third-party.example/api` | unchanged | no |
|
|
627
|
+
|
|
628
|
+
Same-host services on different ports do not inherit the `apiBaseUrl` token. Absolute third-party URLs never inherit that token unless explicitly listed in `authDomains`.
|
|
629
|
+
|
|
630
|
+
**Explicit `authDomains` rule:** when `authDomains` is provided, it remains hostname-based for absolute `http://` and `https://` URLs. Port is stripped because `new URL(fetchUrl).hostname` excludes the port; subdomain matching is supported.
|
|
620
631
|
|
|
621
632
|
| `authDomains` entry | Matches | Does NOT match |
|
|
622
633
|
|---|---|---|
|
|
623
634
|
| `"api.example.com"` | `https://api.example.com/...` (any port) | `https://notapi.example.com`, `https://example.com` |
|
|
624
635
|
| `"example.com"` | `https://example.com`, `https://api.example.com`, `https://foo.example.com` (exact + subdomain) | `https://notexample.com` |
|
|
625
636
|
| `"localhost"` | `http://localhost:5173/...`, `http://localhost:3010/...`, `http://localhost/...` | `http://127.0.0.1` |
|
|
626
|
-
| `"localhost:5173"` | nothing (
|
|
627
|
-
|
|
628
|
-
**Mechanism:** `new URL(fetchUrl).hostname` comparison. Port stripping is a side-effect of the URL API — `.hostname` excludes the port. Subdomain matching: an entry `"example.com"` matches any URL whose hostname ends with `.example.com` (note the leading dot in the comparison — prevents `"api.com"` from matching `"notapi.com"`).
|
|
637
|
+
| `"localhost:5173"` | nothing (domain entries must be hostnames, not `host:port`) | everything |
|
|
629
638
|
|
|
630
|
-
**Dev-mode guidance:**
|
|
639
|
+
**Dev-mode guidance:** prefer `apiBaseUrl` for the app's own backend (`<MythikApp apiBaseUrl="http://localhost:3010" ... />`). If `authDomains` is omitted or empty, Mythik injects Bearer only for that exact `apiBaseUrl` origin. If you provide `authDomains`, the automatic `apiBaseUrl` origin allowlist is disabled; list every trusted absolute host explicitly. Do not add `:port` inside `authDomains[]`.
|
|
631
640
|
|
|
632
|
-
**URL scheme filter:** only `http://` and `https://` URLs are considered
|
|
641
|
+
**URL scheme filter:** only `http://` and `https://` URLs are considered for auth injection. `file:`, `data:`, and other schemes never receive auth headers.
|
|
633
642
|
|
|
634
|
-
Implementation: `packages/core/src/fetch/interceptors/auth.ts
|
|
643
|
+
Implementation: `packages/core/src/fetch/framework-fetch.ts` (base URL resolution) + `packages/core/src/fetch/interceptors/auth.ts` (auth target matching).
|
|
635
644
|
|
|
636
645
|
### 4.2 Contract URL template matching
|
|
637
646
|
|
|
@@ -755,12 +764,12 @@ The persistence layer has distinct paths used at different levels. Understanding
|
|
|
755
764
|
- **`store.save(id, doc)`** - low-level persistence primitive. Accepts `doc: unknown`. No validation. Called by validated orchestration after checks succeed. **Never called from application code** - treat as `@internal`. Calling `store.save()` from your app bypasses validation and produces silently-broken specs.
|
|
756
765
|
- **`store.saveVersion(id, doc, meta)`** - versioned write. Writes a row to `screen_versions` table and updates the current spec. Enables diff/rollback/promote/bisect.
|
|
757
766
|
- **`SpecEngine.patch(id, patches)`** - validated orchestration. Applies RFC-6902 patches, runs DocumentHandler validation, short-circuits on error, and persists the patched document through `store.save`.
|
|
758
|
-
- **CLI/API `mythik push` / `runPush`** - validates and handles `--author` / `author` by writing through `saveVersion` when the resolved store is versioned.
|
|
759
|
-
- **CLI/API `mythik patch` / `runPatch`** - uses `SpecEngine.patch` for patch application + validation.
|
|
767
|
+
- **CLI/API `mythik push` / `runPush`** - validates and handles `--author` / `author` by writing through `saveVersion` when the resolved store is versioned. Existing specs require explicit `--replace` for full replacement.
|
|
768
|
+
- **CLI/API `mythik patch` / `runPatch`** - uses `SpecEngine.patch` for patch application + validation. With a versioned store + `author`, it captures the patched document and writes once through `saveVersion`, so lazy bootstrap preserves the pre-patch current spec as v1 and the patch becomes the next version. JSON/TOON success output includes `versioned: boolean` and `version?: number`. Without `author`, persisted writes are rejected unless `allowUnversioned` / `--allow-unversioned` is explicit.
|
|
760
769
|
|
|
761
770
|
**Consumer rule (to be enforced by Item I linter):** never call `store.save()` from application code. Use:
|
|
762
771
|
|
|
763
|
-
- `mythik push <id>` / `mythik patch <id>` for interactive/shell work
|
|
772
|
+
- `mythik push <id> --from-file spec.json --author <name>` / `mythik patch <id> --from-file patch.json --author <name>` for interactive/shell work
|
|
764
773
|
- `runPush` / `runPatch` from `mythik-cli/api` for programmatic work (Item F exposes these as public exports)
|
|
765
774
|
|
|
766
775
|
Implementation:
|
|
@@ -810,14 +819,14 @@ The framework supports two axes of workflow choice: **how you modify specs** (pu
|
|
|
810
819
|
**Push paradigm:**
|
|
811
820
|
|
|
812
821
|
- Specs live in git under `specs/*.json`
|
|
813
|
-
- Modify locally, run `mythik push <id>`, CLI sends the full spec doc to the DB
|
|
822
|
+
- Modify locally, run `mythik push <id> --from-file spec.json --author <name>`, CLI sends the full spec doc to the DB
|
|
814
823
|
- Diff-reviewable in CI (normal git diff on the JSON file)
|
|
815
824
|
- Full-spec bandwidth cost per write
|
|
816
825
|
|
|
817
826
|
**Patch paradigm:**
|
|
818
827
|
|
|
819
828
|
- Specs live in the DB; local files are optional (working copy)
|
|
820
|
-
- Modify via `mythik patch <id> --from-file patch.json
|
|
829
|
+
- Modify via `mythik patch <id> --from-file patch.json --author <name>` for shell-safe surgical writes
|
|
821
830
|
- ~11x token efficiency vs full push (framework-internal measurement for typical single-element edits)
|
|
822
831
|
- Requires `mythik pull <id>` to sync any local `specs/*.json` snapshot after a DB patch
|
|
823
832
|
|
|
@@ -840,8 +849,11 @@ The framework supports two axes of workflow choice: **how you modify specs** (pu
|
|
|
840
849
|
**Git-backed history:**
|
|
841
850
|
|
|
842
851
|
- Specs in repo, `git log` + `git blame` serve as audit trail
|
|
843
|
-
-
|
|
844
|
-
|
|
852
|
+
- Persisted CLI writes must still be explicit: use `--author <name>`
|
|
853
|
+
whenever the resolved store supports versioning, or
|
|
854
|
+
`--allow-unversioned` only when the project intentionally uses a
|
|
855
|
+
non-versioned store
|
|
856
|
+
- CLI writes via `store.save` only on the explicit unversioned path (see §5.4)
|
|
845
857
|
- Best for: single-env apps, dev-loop iteration, specs-as-code
|
|
846
858
|
|
|
847
859
|
**DB-versioned history:**
|
|
@@ -921,7 +933,7 @@ The `$state` resolves at click time against the just-written `/ui/selectedRow`.
|
|
|
921
933
|
|
|
922
934
|
**Root:** §4.1 — matcher uses `parsed.hostname` (strips port). Entry `"localhost:5173"` never matches any URL's hostname (which is just `"localhost"`).
|
|
923
935
|
|
|
924
|
-
**Solution:** `
|
|
936
|
+
**Solution:** prefer `apiBaseUrl: "http://localhost:3010"` on the host app for the app's own backend. If you intentionally need an explicit additional host, use `authDomains: ["localhost"]`, not `["localhost:5173"]`.
|
|
925
937
|
|
|
926
938
|
### 7.5 Wiring a reactive data source with a debounced filter
|
|
927
939
|
|
|
@@ -1012,7 +1024,8 @@ Login spec binds input to `/login/email`; `loginBody` maps it to `username` at d
|
|
|
1012
1024
|
- `packages/core/src/device/context.ts` — DeviceContext interface
|
|
1013
1025
|
|
|
1014
1026
|
**Fetch + auth:**
|
|
1015
|
-
- `packages/core/src/fetch/
|
|
1027
|
+
- `packages/core/src/fetch/framework-fetch.ts` — `apiBaseUrl` resolution
|
|
1028
|
+
- `packages/core/src/fetch/interceptors/auth.ts` — auth target matcher
|
|
1016
1029
|
|
|
1017
1030
|
**Server:**
|
|
1018
1031
|
- `packages/server/src/server.ts:104-116` — `/api/auth/login` endpoint
|
|
@@ -88,7 +88,7 @@ Every screen is a flat tree: `root` ID + `elements` map + optional `initialActio
|
|
|
88
88
|
| `style` | object | CSS styles (can contain expressions) |
|
|
89
89
|
| `visible` | expression | Show/hide condition |
|
|
90
90
|
| `permission` | object | `{ visible, editable, readonly }` per role |
|
|
91
|
-
| `repeat` | object | Iterate over array: `{ statePath, key }` or `{ source, key }` |
|
|
91
|
+
| `repeat` | object | Iterate over array: `{ statePath, key }` or `{ source, key }`; optional `layout` controls item row direction/gap/wrap |
|
|
92
92
|
| `on` | object | Event handlers: `{ press, change, submit }` |
|
|
93
93
|
| `hover` | object | Style overrides on pointer enter |
|
|
94
94
|
| `active` | object | Style overrides on press |
|
|
@@ -108,10 +108,17 @@ mythik init-store --dialect postgres --dry-run # Print SQL store DDL f
|
|
|
108
108
|
mythik init-store --dialect sqlserver --server localhost --database Mythik --user "$DB_USER" --password "$DB_PASSWORD" --encrypt false --trust-server-certificate
|
|
109
109
|
mythik manifest <screen> # See structural tree
|
|
110
110
|
mythik elements <screen> <id1,id2> # Get element details
|
|
111
|
-
mythik patch <screen> --from-file patch.json # Apply RFC 6902 patches
|
|
111
|
+
mythik patch <screen> --from-file patch.json --author <agent> # Apply versioned RFC 6902 patches
|
|
112
112
|
mythik pull <screen> # Export full spec for backup/review
|
|
113
|
-
mythik push <screen>
|
|
113
|
+
mythik push <screen> --from-file spec.json --author <agent> # Create a new spec
|
|
114
|
+
mythik push <screen> --from-file spec.json --replace --author <agent> # Intentional full replacement
|
|
114
115
|
mythik validate <screen> # Validate spec
|
|
116
|
+
mythik reveal start # Start local runtime context bridge
|
|
117
|
+
mythik reveal apps --json # List connected running apps
|
|
118
|
+
mythik reveal context --app <name> # Read live app contract/state/diagnostics
|
|
119
|
+
mythik reveal element <id> --app <name> # Inspect one live element
|
|
120
|
+
mythik agent init codex|claude|all # Install project-local AI operating protocol
|
|
121
|
+
mythik agent context --app <app-id> --include-screens --out .mythik/agent/context.md
|
|
115
122
|
```
|
|
116
123
|
|
|
117
124
|
### Required edit loop for existing specs
|
|
@@ -121,20 +128,78 @@ When an AI agent modifies an existing Mythik spec, use this loop by default:
|
|
|
121
128
|
1. `mythik manifest <screen>` - inspect the current structure and identify candidate element IDs.
|
|
122
129
|
2. `mythik elements <screen> <id1,id2,...>` - inspect only the exact elements and nearby containers that will change.
|
|
123
130
|
3. Write a small RFC 6902 patch file.
|
|
124
|
-
4. `mythik patch <screen> --from-file patch.json
|
|
125
|
-
5.
|
|
131
|
+
4. `mythik patch <screen> --from-file patch.json --author <agent>` - apply the surgical change through the validated, versioned CLI path.
|
|
132
|
+
5. Run `mythik validate <screen>`.
|
|
133
|
+
6. Re-run `mythik manifest <screen>` or `mythik elements <screen> <ids>` to verify the changed surface.
|
|
126
134
|
|
|
127
135
|
Do not edit database rows directly, do not call `SpecStore.save()` from app code, and do not replace a whole screen with `push` when a targeted `patch` can express the change. `pull` is for backup, migration, review, or full-spec creation workflows; it is not the normal first step for a small edit.
|
|
128
136
|
|
|
129
|
-
|
|
137
|
+
Mythik Sentinel is built into the CLI to help fresh agents stay on that loop. It prints advisory guidance on first project use and when it detects repeated full-replacement intent with little/no patch usage. Sentinel is best-effort: it does not change command exit codes, it does not store specs or credentials, and it preserves JSON/TOON machine-readable outputs. Disable only for exceptional automation with `MYTHIK_SENTINEL=off`.
|
|
130
138
|
|
|
131
|
-
**Patch
|
|
139
|
+
**Patch rules:** `"op": "add"` with numeric index **inserts before** (not replace). Use `/-` to append. Use `"op": "replace"` to overwrite. Prefer `mythik patch <id> --from-file patch.json --author <agent>` for any patch containing `$state`, `$template`, `$auth`, or other shell-sensitive strings.
|
|
140
|
+
|
|
141
|
+
**Patch input precedence:** explicit sources win. `--from-file <path>` reads that file even if the host process has non-TTY stdin (common in PowerShell/agent runners). Stdin still works via `--from-file -` or by piping without `--from-file`: `cat patch.json | mythik patch <id> --author <agent>`.
|
|
132
142
|
|
|
133
143
|
All commands accept `--json`, `--table <name>`, `--store`, `--url`, `--key`. Never pass API keys inline — use `.mythikrc` + env vars.
|
|
134
144
|
|
|
145
|
+
### Mythik Reveal: live context for AI agents
|
|
146
|
+
|
|
147
|
+
Use Mythik Reveal when debugging or changing a running app. Lint,
|
|
148
|
+
validate, `manifest`, and `elements` inspect stored specs; Reveal
|
|
149
|
+
inspects the live runtime. It exposes the active renderer, environment,
|
|
150
|
+
mounted spec summary, selected screen/element, resolved public props,
|
|
151
|
+
included state paths, render errors, warnings, and action/dataSource
|
|
152
|
+
events as structured JSON.
|
|
153
|
+
|
|
154
|
+
Start the local bridge:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
mythik reveal start --port 17373
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Pass the printed `MYTHIK_REVEAL_URL` and `MYTHIK_REVEAL_TOKEN` to the
|
|
161
|
+
host app's `reveal` config. In React, memoize the object so the bridge
|
|
162
|
+
client is stable:
|
|
163
|
+
|
|
164
|
+
```tsx
|
|
165
|
+
const reveal = React.useMemo(() => ({
|
|
166
|
+
enabled: import.meta.env.DEV,
|
|
167
|
+
appName: 'my-app',
|
|
168
|
+
bridgeUrl: import.meta.env.VITE_MYTHIK_REVEAL_URL,
|
|
169
|
+
token: import.meta.env.VITE_MYTHIK_REVEAL_TOKEN,
|
|
170
|
+
environment: { id: 'dev', source: 'host' as const },
|
|
171
|
+
includeStatePaths: ['/ui', '/form'],
|
|
172
|
+
redactStatePaths: ['/auth', '/secrets'],
|
|
173
|
+
}), []);
|
|
174
|
+
|
|
175
|
+
<MythikApp appSpec={appSpec} specStore={specStore} reveal={reveal} />
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Then inspect the running app:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
mythik reveal apps --json
|
|
182
|
+
mythik reveal context --app my-app
|
|
183
|
+
mythik reveal current --app my-app
|
|
184
|
+
mythik reveal screen dashboard --app my-app
|
|
185
|
+
mythik reveal element save-button --app my-app
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
For React Native Android emulator smoke, reverse the bridge port:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
adb reverse tcp:17373 tcp:17373
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Reveal is development tooling. Do not enable it in production, do not
|
|
195
|
+
commit tokens, and expose only the state paths the agent needs.
|
|
196
|
+
Redact auth, secrets, tokens, passwords, API keys, and session values.
|
|
197
|
+
When a runtime symptom is visible but the cause is unknown, agents
|
|
198
|
+
should ask Reveal before proposing a patch.
|
|
199
|
+
|
|
135
200
|
### CLI store configuration
|
|
136
201
|
|
|
137
|
-
The CLI can read and write specs from `memory`, `file`, `supabase`, `sqlserver`, `postgres`, `mysql`, and `sqlite` stores. SQL stores share the same commands and the same required edit loop: `manifest -> elements -> patch -> validate`.
|
|
202
|
+
The CLI can read and write specs from `memory`, `file`, `supabase`, `sqlserver`, `postgres`, `mysql`, and `sqlite` stores. SQL stores share the same commands and the same required edit loop: `manifest -> elements -> patch --from-file --author -> validate -> verify`.
|
|
138
203
|
|
|
139
204
|
```bash
|
|
140
205
|
# SQLite: local development, tests, demos, lightweight deployments
|
|
@@ -166,12 +231,14 @@ Environment equivalents: `MYTHIK_STORE`, `MYTHIK_DATABASE_URL`, `MYTHIK_SQLITE_F
|
|
|
166
231
|
|
|
167
232
|
Per reference-doc rule 248: three approved forms.
|
|
168
233
|
|
|
169
|
-
- **Shell**: `mythik push <id> --from-file spec.json
|
|
170
|
-
- **Bulk**: `mythik push --from-dir <folder>` — sequential per-file push of every `*.json`. Continue-on-error: failures don't stop subsequent specs. No rollback. Partial state recovers by fixing failures and re-running.
|
|
234
|
+
- **Shell**: `mythik push <id> --from-file spec.json --author <agent>` and `mythik patch <id> --from-file patch.json --author <agent>` (cross-shell ergonomic for any spec/patch containing `$state`, `$template`, `$auth`, or `$row`)
|
|
235
|
+
- **Bulk**: `mythik push --from-dir <folder> --author <agent>` — sequential per-file push of every `*.json`. Continue-on-error: failures don't stop subsequent specs. No rollback. Partial state recovers by fixing failures and re-running.
|
|
171
236
|
- **Programmatic**: `import { runPush, runPatch, parsePatchInput, type PushResult } from 'mythik-cli/api'` — same code path as the binary, no shell. Pass `json: true` in options to receive structured command output via `JSON.parse(result.output)`. `runPatch` success output includes `versioned: boolean` and `version?: number` when a versioned store + `author` creates history.
|
|
172
237
|
|
|
173
238
|
`SpecStore.save()` is `@internal` — calling it from application code skips validation and produces runtime errors only at render time. The three forms above are the only validated paths.
|
|
174
239
|
|
|
240
|
+
Existing persisted specs are protected by the Agent Protocol: full replacements require `--replace`, and persisted writes require `--author <name>` for versioned stores or explicit `--allow-unversioned` for intentionally unversioned stores.
|
|
241
|
+
|
|
175
242
|
### Pre-push linting
|
|
176
243
|
|
|
177
244
|
Run `mythik lint` to detect anti-patterns before pushing. Three approved invocations:
|
|
@@ -450,7 +517,7 @@ Any action binding may include `params.skipIf`. Mythik resolves `skipIf` at disp
|
|
|
450
517
|
- Sets `/ui/loading` while in flight
|
|
451
518
|
- On error: sets `/ui/lastError` with status and message
|
|
452
519
|
- Optional `errorTarget` writes the same structured error to a screen-owned path and clears that path on success. Use it for critical screen-load fetches instead of relying only on global `/ui/lastError`
|
|
453
|
-
- Auth headers auto-injected for `authDomains`
|
|
520
|
+
- Auth headers auto-injected for `apiBaseUrl` exact-origin framework URLs and explicit `authDomains` hosts
|
|
454
521
|
|
|
455
522
|
### Transactions (Optimistic Updates)
|
|
456
523
|
|
|
@@ -556,6 +623,18 @@ Chain: `$array: "filter"` → `$array: "search"` → `$array: "slice"` for filte
|
|
|
556
623
|
|
|
557
624
|
Inside repeated elements: `$item`, `$index`, `$bindItem` access current item.
|
|
558
625
|
|
|
626
|
+
Repeated rows can opt into horizontal/wrapping layout without changing the child primitive:
|
|
627
|
+
|
|
628
|
+
```json
|
|
629
|
+
"repeat": {
|
|
630
|
+
"source": { "$state": "/filters" },
|
|
631
|
+
"key": "id",
|
|
632
|
+
"layout": { "direction": "horizontal", "gap": 8, "wrap": true }
|
|
633
|
+
}
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
For grouped repeats, group headers and footers remain vertical; `repeat.layout` applies only to each group's item row.
|
|
637
|
+
|
|
559
638
|
### Grouped Repeat
|
|
560
639
|
|
|
561
640
|
**Client-side** (engine groups flat array): `groupBy: "category"`
|
|
@@ -855,7 +934,7 @@ Interceptors:
|
|
|
855
934
|
"interceptors": { "logging": true, "timeout": { "ms": 15000 }, "retryOnError": { "maxRetries": 2, "statuses": [502, 503] } }
|
|
856
935
|
```
|
|
857
936
|
|
|
858
|
-
Security: tokens NEVER in state (engine closure only). `$auth` blocks token/password fields. Auth headers only for `authDomains`. Credentials cleared after login. Rate limit: 5/min. Cross-tab sync automatic.
|
|
937
|
+
Security: tokens NEVER in state (engine closure only). `$auth` blocks token/password fields. Auth headers are injected only for the host `apiBaseUrl` exact origin or explicit `authDomains`. Credentials cleared after login. Rate limit: 5/min. Cross-tab sync automatic.
|
|
859
938
|
|
|
860
939
|
Custom JWT provider response mapping: `tokenPath`, `refreshTokenPath`, and `userPath` are dot paths against the full login/refresh response. `rolePath` and `rolesPath` use a compat dual contract: plain keys like `"role"` / `"roles"` resolve inside the extracted `userPath` object; dotted paths like `"user.role"` or `"data.user.role"` resolve against the full response. If no role or roles are found, Mythik uses `defaultRole` (`"user"` by default) and warns in development.
|
|
861
940
|
|
|
@@ -1167,7 +1246,7 @@ Reference: `"hover": { "$token": "motion.presets.hoverLift" }`
|
|
|
1167
1246
|
|
|
1168
1247
|
## Component Variants
|
|
1169
1248
|
|
|
1170
|
-
Token-driven styling. Define in `tokens.components.{type}.{variant}`:
|
|
1249
|
+
Token-driven styling. **Use this before copying the same style block into multiple elements.** Define in `tokens.components.{type}.{variant}` and reference it from `props.variant`:
|
|
1171
1250
|
|
|
1172
1251
|
```json
|
|
1173
1252
|
"tokens": {
|
|
@@ -1184,7 +1263,9 @@ Token-driven styling. Define in `tokens.components.{type}.{variant}`:
|
|
|
1184
1263
|
```
|
|
1185
1264
|
Usage: `{ "type": "button", "props": { "label": "Save", "variant": "primary" } }`
|
|
1186
1265
|
`$path` references (`$colors.primary`) resolve against active tokens — dark mode works automatically.
|
|
1187
|
-
Element-level style/hover overrides variant (variant is base, element is override). Supports: `style`, `hover`, `active`, `focus`, `transition`.
|
|
1266
|
+
Element-level style/hover overrides variant (variant is base, element is override). Supports: `style`, `hover`, `active`, `focus`, `transition`.
|
|
1267
|
+
|
|
1268
|
+
Important boundary: variants are for primitive visual slots. They do **not** carry arbitrary primitive props such as `table.headerStyle`, `table.rowStyle`, `columns`, or action bindings. For prop-bearing reusable patterns, define an AppSpec `templates` entry and use `$prop` to pass through data/columns/actions. Example: use `tokens.components.box.tableCard` for card styling, but use an `ops-table` template when several tables need the same `headerStyle` + `rowStyle` chrome. For composed filter chips (`touchable` + `text`), put static shared styling in variants and keep state/item-specific active colors on the element.
|
|
1188
1269
|
|
|
1189
1270
|
## Skeleton & Export
|
|
1190
1271
|
|
|
@@ -1401,8 +1482,8 @@ When the framework changes the schema in a future version, this section will gai
|
|
|
1401
1482
|
28. loginScreen always accessible — prevents redirect loops
|
|
1402
1483
|
29. Login renders fullscreen (no layout) — appears automatically when not authenticated
|
|
1403
1484
|
30. Login paths: `/screens/login/...` not `/form/...` — clears on logout with statePolicy reset
|
|
1404
|
-
31. Auth headers auto-injected for `authDomains` — no manual headers in fetch
|
|
1405
|
-
32. Use `variant` prop for
|
|
1485
|
+
31. Auth headers auto-injected for `apiBaseUrl` exact-origin framework URLs and explicit `authDomains` hosts — no manual headers in fetch
|
|
1486
|
+
32. Use `variant` prop for reusable primitive styling — don't copy style objects; put `variant` inside `props`
|
|
1406
1487
|
33. `$path` references in variants resolve with dark mode automatically
|
|
1407
1488
|
34. Use `mythik push` for spec creation — no seed scripts
|
|
1408
1489
|
35. AppSpec patches use `/layout/elements/` not `/elements/`
|
|
@@ -1437,11 +1518,11 @@ When the framework changes the schema in a future version, this section will gai
|
|
|
1437
1518
|
64. Custom element black-box boundary — consumer's instance-level `animations`, `hover`, `active`, `focus`, `motion`, `style`, `visible`, and `key` apply to the OUTER primitive only. Inner primitives are the author's domain and are not reachable from the consumer. Identity cascade (rule 63 / cascade level 1) still reaches inner primitives; consumer cannot override them directly
|
|
1438
1519
|
65. `$prop` is nearest-enclosing-custom-element-scoped — inside a custom element's render tree, `$prop` resolves against THAT element's merged props. Nesting a custom element inside another pushes a new prop context; the outer's props are shadowed, not merged. Pass values explicitly via prop declarations when nested access is needed
|
|
1439
1520
|
66. `$children` marker in custom element render trees — authors write `"$children"` as a string item in their render tree `children` array to mark where consumer children are inserted during expansion. Multiple markers each splice the full consumer children. Same slotting semantics as spec templates
|
|
1440
|
-
67. `variant` is a PROP — place it inside `props`, never as a top-level element field. Applies to built-in primitives and Layer 3 custom elements alike: `{ "type": "stat-card", "props": { "variant": "primary", ... } }`. Top-level `variant` is silently ignored (the renderer reads `props.variant` only). Consumer may drive it dynamically via an expression
|
|
1521
|
+
67. `variant` is a PROP — place it inside `props`, never as a top-level element field. Applies to built-in primitives and Layer 3 custom elements alike: `{ "type": "stat-card", "props": { "variant": "primary", ... } }`. Top-level `variant` is silently ignored (the renderer reads `props.variant` only). Consumer may drive it dynamically via an expression. Variants are style/interaction slots only; use templates/custom elements when the reusable pattern must carry props like table `headerStyle`/`rowStyle` or composed children.
|
|
1441
1522
|
68. Custom elements may expose action-chain props — author declares a prop (e.g. `onSelect`, type `"array"`) and the render tree's `on:<event>` references it as `{ "$prop": "onSelect" }`. Consumers supply the full action array as the prop value; inner `$state` / `$template` / `$item` inside those actions resolve at press time with the current state (not at render time). Enables tabs, menu items, and similar patterns where the consumer owns the action chain
|
|
1442
1523
|
69. Never use `$row` literal — there is no `$row` expression handler. Read row data via `$state: '/ui/selectedRow/<key>'` (framework writes clicked row before column action dispatch).
|
|
1443
1524
|
70. Never combine `crud: {}` with `endpoint.path` ending in `/:id`. CRUD operations auto-append `/:id` to PUT/DELETE routes. Declaring `path: '/api/x/:id'` produces `/api/x/:id/:id`.
|
|
1444
|
-
71.
|
|
1525
|
+
71. Prefer `MythikApp apiBaseUrl` for the app's own backend. Relative runtime URLs (`/api/...`) resolve against that base and inherit auth only for the exact base origin when `authDomains` is omitted or empty. Providing `authDomains` disables the automatic `apiBaseUrl` origin allowlist; list every trusted absolute host explicitly. Never include `:port` in `auth.authDomains[]` entries because that matcher uses hostnames.
|
|
1445
1526
|
72. `spatial-map` is the generic SVG/data-first primitive for floor plans, seating maps, parking maps, warehouse layouts, hospital beds, and similar spatial workflows. JSON `onItemPress` actions write item context to `/ui/selectedSpatialItem` before lazy dispatch. Compose domain menus/drawers/modals externally; do not encode restaurant-specific behavior into the primitive. Use `{ "$state": "/path" }` expressions for dynamic `items`, `zones`, `mode`, and `statusStyles`; do not invent `*Path` prop aliases.
|
|
1446
1527
|
73. For `spatial-map` editing, use `editPolicy` for movement rules and `onItemChange` for persistence. Do not use `interactionPolicy` for drag/keyboard movement. In JSON specs, persist moved items with `$array: "replace"` reading from `/ui/spatialItemChange` or the configured `itemChangePath`; use plain `setState` for non-undoable screens and wrap the same value in `editorCommit` for undoable editors.
|
|
1447
1528
|
74. For JSON-created client-side item ids, use `$uniqueId` with an explicit `source`, `field`, `prefix`, and optional `padding`. It is deterministic and scoped to the source array; use it for local/editor objects, not as a substitute for database primary keys when a backend owns identity.
|
|
@@ -1456,12 +1537,12 @@ When the framework changes the schema in a future version, this section will gai
|
|
|
1456
1537
|
82. Use `editorSessions.<id>.persistence` plus `editorSave` for generic editor document persistence. The AI should not hand-compose `transaction` + `editorMarkSaved` for normal editor saves. `editorSave` captures the tracked paths snapshot, persists it through the host fetcher with URL-guard checks, and marks only the sent snapshot as saved after success. Failed saves keep `dirty: true` and expose save metadata under `/ui/editorSessions/<id>`.
|
|
1457
1538
|
83. Use `navigation.editorSessionGuard` for generic unsaved-changes protection in app specs instead of hand-rolled JSON dirty checks. Configure `sessions`, render your own JSON modal from `/ui/navigationGuard/pending`, call `navigationGuardCancel`, `navigationGuardSaveAndProceed`, `navigationGuardProceed`, or `navigationGuardDiscardAndProceed`, and keep `pendingPath` under a consumer-owned `/ui/<segment>` path that does not collide with reserved framework paths. `navigationGuardSaveAndProceed` is the normal save-first UX for persisted editor sessions; `navigationGuardProceed` is a low-level non-destructive retry that only resumes after the pending editor sessions are already clean; use `navigationGuardDiscardAndProceed` when the user explicitly chooses to abandon unsaved tracked-path changes.
|
|
1458
1539
|
84. In React apps without auth framework fetch, pass `fetcher` to `MythikApp` when editor sessions use `editorSave` or `navigationGuardSaveAndProceed`. Auth-enabled apps continue to use the framework fetch produced by auth interceptors. Do not route save-and-continue through `/ui/lastError` or a hand-composed fetch action; the editor session engine owns save metadata under `/ui/editorSessions/<id>`.
|
|
1459
|
-
85. For existing spec edits, the required AI loop is `mythik manifest` -> `mythik elements` -> `mythik patch --from-file` -> verify. Manifest tells you the structure; elements gives the exact JSON you are changing; patch is the validated write path. Do not skip directly to full-spec `pull`/rewrite/push for a local change, do not mutate DB rows manually, and do not call `SpecStore.save()` from app code. Use `push` for new specs or intentional full replacement only
|
|
1540
|
+
85. For existing spec edits, the required AI loop is `mythik manifest` -> `mythik elements` -> `mythik patch --from-file --author` -> `mythik validate` -> verify. Manifest tells you the structure; elements gives the exact JSON you are changing; patch is the validated write path. Do not skip directly to full-spec `pull`/rewrite/push for a local change, do not mutate DB rows manually, and do not call `SpecStore.save()` from app code. Use `push` for new specs or intentional full replacement only; existing specs require explicit `--replace`.
|
|
1460
1541
|
86. Mythik's AI documentation ships with the `mythik` npm package. Before generating or modifying specs, locate it with `mythik docs path` and start from `docs/llms.txt`, `docs/consumer/ai-context.md`, and `docs/wiki/compiled/README.md`. Use `mythik docs copy ./mythik-docs` when a project-local copy is easier to hand to an AI agent.
|
|
1461
1542
|
87. DNA numeric seeds (`roundness`, `density`, `depth`, `formality`) are canonical `0–1` values. Generate `0.7`, not `70`. The runtime tolerates legacy `0–100` values by normalizing any numeric seed greater than `1` with `/100` during DNA derivation, including initial AppSpec load and runtime `updateTokens`.
|
|
1462
1543
|
88. API query endpoints can combine `pagination: "offset"` with `scopeFilter`. For generated counts, Mythik applies the scope filter to the source query before `COUNT(*)`, so paginated totals remain tenant-scoped. Prefer generated counts. If a custom `endpoint.count` is truly needed with `scopeFilter`, include `{{scopeWhere[:alias]}}` or `{{scopeAnd[:alias]}}`; Mythik expands the macro to the correct scope predicate and removes it for bypass roles. Other custom count SQL is left verbatim. Use `:alias` for JOIN/subquery counts, and do not reference internal scope params directly.
|
|
1463
1544
|
89. Transaction `confirm` failures from `fetch` preserve backend error details for `onError`. Read `/tx/error/message` for the best available message; when the backend returns `{ error: { code, message } }`, Mythik keeps that message, `code`, HTTP `status`, and raw `data` after rollback. Do not parse `/ui/lastError` from transaction specs.
|
|
1464
|
-
90. For SQL-backed stores and servers, use the generic `mythik/server` SQL boundary. Initialize tables with `mythik init-store --dialect <sqlserver|postgres|mysql|sqlite>` or inspect DDL with `--dry-run`; configure the CLI with `--store`, `--url`/`--filename`/SQL Server flags, or `MYTHIK_*` environment variables; and keep spec edits on the required `manifest -> elements -> patch --from-file -> validate` loop. Write custom API SQL in the selected dialect with Mythik named params (`@name`); Mythik does not translate custom SQL between dialects.
|
|
1545
|
+
90. For SQL-backed stores and servers, use the generic `mythik/server` SQL boundary. Initialize tables with `mythik init-store --dialect <sqlserver|postgres|mysql|sqlite>` or inspect DDL with `--dry-run`; configure the CLI with `--store`, `--url`/`--filename`/SQL Server flags, or `MYTHIK_*` environment variables; and keep spec edits on the required `manifest -> elements -> patch --from-file --author -> validate -> verify` loop. Write custom API SQL in the selected dialect with Mythik named params (`@name`); Mythik does not translate custom SQL between dialects.
|
|
1465
1546
|
91. Event arrays may mix normal actions and transaction bindings. Mythik executes them sequentially and awaits each transaction before continuing. Use this when a flow needs a small action before or after an optimistic transaction; do not wrap a transaction inside another transaction phase.
|
|
1466
1547
|
92. `$ref` and `$template` placeholders can read nested values from `$let` object bindings with dot notation, for example `{ "$ref": "user.name" }` or `${user.name}`. If a dotted `$ref` segment is missing, runtime throws an unknown `$ref` error rather than silently returning undefined.
|
|
1467
1548
|
93. Use `params.skipIf` for a dispatch-time action guard when an action should be skipped but the surrounding action chain should continue. `skipIf` is resolved before other params and is removed before the action handler runs. Do not use `skipIf` as a substitute for form validation or transaction rollback.
|
|
@@ -1470,3 +1551,8 @@ When the framework changes the schema in a future version, this section will gai
|
|
|
1470
1551
|
96. SQL adapters are optional peer dependencies, not installed-by-default runtime payload. Browser-only apps install `mythik mythik-react` without database drivers. SQL-backed stores/servers must install exactly one selected adapter: `mssql`, `pg`, `mysql2`, or `better-sqlite3`. SQLite uses native `better-sqlite3`; native-build helper warnings from that adapter are not Mythik runtime failures.
|
|
1471
1552
|
97. Missing SQL adapter errors are actionable. The thrown `SqlDriverError` includes `packageName`, `installCommand`, and a message with the exact `npm install ...` command for the selected dialect.
|
|
1472
1553
|
98. For native Expo apps, install renderer peer packages with `npx expo install react-native-svg react-native-reanimated react-native-worklets ...` before installing `mythik mythik-react-native`, so Expo selects native module versions that match the app SDK. Keep `react-native-reanimated/plugin` last in the app Babel config. Keep `root` as a stable string element id; use `$platform` only inside localized props, style, children, or values. `$platform` matches exact platform keys first, then falls back from `ios`/`android` to `native`; it has no `default` key. Before using a primitive in native specs, check `REACT_NATIVE_PRIMITIVE_SUPPORT` or `getReactNativePrimitiveSupport` from `mythik-react-native`; native-milestone primitives should fail visibly instead of being treated as supported.
|
|
1554
|
+
99. Use Mythik Reveal before guessing about running-app behavior. Start `mythik reveal start`, wire the host `reveal` config in development, then inspect with `mythik reveal apps`, `context`, `current`, `screen`, or `element`. Reveal returns live renderer/environment/spec/state/diagnostics/events with redaction, so agents can diagnose runtime behavior from structured context instead of screenshots, stale pulled specs, or source-code assumptions. Never enable Reveal in production, never commit the token, and include/redact state paths deliberately.
|
|
1555
|
+
100. **Use Mythik Agent Context, Agent Protocol, and Sentinel for fresh AI agents**. Run `mythik agent init codex`, `mythik agent init claude`, or `mythik agent init all` to install project-local agent instructions. `codex` creates/updates `AGENTS.md`, `claude` creates/updates `CLAUDE.md`, and `all` updates both; existing file content outside the Mythik-managed `<!-- mythik-agent-protocol:start -->` / `<!-- mythik-agent-protocol:end -->` block is preserved. Generate live project context with `mythik agent context --app <id> --include-screens --out .mythik/agent/context.md`. Existing stored specs stay on `manifest -> elements -> patch --from-file --author -> validate -> verify`. The active store is the source of truth; local spec files are drafts/snapshots/migrations/fixtures unless a file store is intentionally configured. Use TOON for large reads when supported, and use `mythik lint` for new local drafts, replacement files, bulk imports/migrations, and relevant consumer code changes. Mythik Sentinel runs from the CLI as advisory coaching: first project use reminds the agent to initialize instructions, repeated full replacement intent warns the agent back to patch-first edits, identical `push --replace` writes are skipped as `skipped: true`, and no spec contents or credentials are persisted in the Sentinel cache. Disable only with `MYTHIK_SENTINEL=off` for exceptional automation.
|
|
1556
|
+
101. `repeat.layout` controls repeated item rows (`direction`, `gap`, `wrap`). In grouped repeats, headers/footers remain vertical and the layout applies only to the group item row.
|
|
1557
|
+
102. `select` normalizes option identity for display: DB integer IDs and string option values match, `0` is a valid selected value, and null/undefined show the placeholder. Values emitted by existing `onChange` remain string-compatible.
|
|
1558
|
+
103. `text.on.press` is supported for inline interactive text. Web receives button semantics plus keyboard activation; React Native receives `accessibilityRole="button"`. Use `button` or `touchable` for primary/larger actions.
|