mythik 0.2.0 → 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 +68 -44
- 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/contract/extractor.js +3 -0
- package/dist/contract/extractor.js.map +1 -1
- package/dist/data/data-sources.d.ts +4 -0
- package/dist/data/data-sources.d.ts.map +1 -1
- package/dist/data/data-sources.js +3 -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/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/runtime/mount-spec-runtime.d.ts +2 -0
- package/dist/runtime/mount-spec-runtime.d.ts.map +1 -1
- package/dist/runtime/mount-spec-runtime.js +4 -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/ai-context-patterns.md +42 -7
- package/docs/consumer/ai-context-primitives.md +25 -2
- package/docs/consumer/ai-context-runtime-semantics.md +36 -26
- package/docs/consumer/ai-context.md +57 -38
- package/docs/consumer/reference-doc.md +97 -59
- package/docs/wiki/compiled/concept-component-variants.md +39 -10
- package/docs/wiki/compiled/concept-templates-vs-variants.md +77 -13
- package/docs/wiki/compiled/pattern-reusable-components.md +42 -12
- package/package.json +1 -1
|
@@ -34,28 +34,28 @@ mythik manifest <screen>
|
|
|
34
34
|
# Get specific element details
|
|
35
35
|
mythik elements <screen> <id1,id2,...>
|
|
36
36
|
|
|
37
|
-
# Apply RFC 6902 patches
|
|
38
|
-
mythik patch <screen> --from-file patch.json --author <agent>
|
|
37
|
+
# Apply RFC 6902 patches
|
|
38
|
+
mythik patch <screen> --from-file patch.json --author <agent>
|
|
39
39
|
|
|
40
40
|
# Export a full screen spec for backup/review
|
|
41
41
|
mythik pull <screen>
|
|
42
42
|
|
|
43
|
-
# Create a new screen spec or intentionally replace a full screen spec
|
|
44
|
-
mythik push <screen> --from-file spec.json --author <agent>
|
|
45
|
-
mythik push <screen> --from-file spec.json --replace --author <agent>
|
|
43
|
+
# Create a new screen spec or intentionally replace a full screen spec
|
|
44
|
+
mythik push <screen> --from-file spec.json --author <agent>
|
|
45
|
+
mythik push <screen> --from-file spec.json --replace --author <agent>
|
|
46
46
|
|
|
47
47
|
# Validate a screen spec
|
|
48
48
|
mythik validate <screen>
|
|
49
49
|
|
|
50
|
-
# Start and query live runtime context for AI agents
|
|
51
|
-
mythik reveal start
|
|
52
|
-
mythik reveal apps --json
|
|
53
|
-
mythik reveal context --app <name>
|
|
54
|
-
mythik reveal element <element-id> --app <name>
|
|
55
|
-
|
|
56
|
-
# Install and refresh project-local AI operating context
|
|
57
|
-
mythik agent init codex|claude|all
|
|
58
|
-
mythik agent context --app <app-id> --include-screens --out .mythik/agent/context.md
|
|
50
|
+
# Start and query live runtime context for AI agents
|
|
51
|
+
mythik reveal start
|
|
52
|
+
mythik reveal apps --json
|
|
53
|
+
mythik reveal context --app <name>
|
|
54
|
+
mythik reveal element <element-id> --app <name>
|
|
55
|
+
|
|
56
|
+
# Install and refresh project-local AI operating context
|
|
57
|
+
mythik agent init codex|claude|all
|
|
58
|
+
mythik agent context --app <app-id> --include-screens --out .mythik/agent/context.md
|
|
59
59
|
|
|
60
60
|
# Delete a screen (preview without --confirm)
|
|
61
61
|
mythik delete <screen> --confirm
|
|
@@ -83,15 +83,15 @@ Set the env var once per session: `export MYTHIK_API_KEY="your-key"`. The CLI re
|
|
|
83
83
|
### Patch Input: File vs Stdin
|
|
84
84
|
|
|
85
85
|
**Preferred shell-safe path** - write patch JSON to a file:
|
|
86
|
-
```bash
|
|
87
|
-
mythik patch task-manager --from-file patch.json --author <agent>
|
|
88
|
-
```
|
|
86
|
+
```bash
|
|
87
|
+
mythik patch task-manager --from-file patch.json --author <agent>
|
|
88
|
+
```
|
|
89
89
|
|
|
90
90
|
`--from-file <path>` wins over ambient non-TTY stdin. Use `--from-file -` or pipe without `--from-file` when stdin is intentional:
|
|
91
|
-
```bash
|
|
92
|
-
cat patch.json | mythik patch task-manager --author <agent>
|
|
93
|
-
mythik patch task-manager --from-file - --author <agent>
|
|
94
|
-
```
|
|
91
|
+
```bash
|
|
92
|
+
cat patch.json | mythik patch task-manager --author <agent>
|
|
93
|
+
mythik patch task-manager --from-file - --author <agent>
|
|
94
|
+
```
|
|
95
95
|
|
|
96
96
|
Inline JSON still works for tiny patches, but `--from-file` is preferred for anything containing `$state`, `$template`, `$auth`, or shell-sensitive quoting.
|
|
97
97
|
|
|
@@ -101,9 +101,9 @@ Inline JSON still works for tiny patches, but `--from-file` is preferred for any
|
|
|
101
101
|
|
|
102
102
|
Use `--toon` for token-efficient output on `elements` and `patch` commands:
|
|
103
103
|
|
|
104
|
-
```bash
|
|
105
|
-
mythik elements task-manager btn,nav --toon
|
|
106
|
-
mythik patch task-manager --from-file patch.toon --toon --author <agent>
|
|
104
|
+
```bash
|
|
105
|
+
mythik elements task-manager btn,nav --toon
|
|
106
|
+
mythik patch task-manager --from-file patch.toon --toon --author <agent>
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
TOON reduces output by ~40% vs JSON. Lossless roundtrip. Based on `@toon-format/toon` v2.
|
|
@@ -112,22 +112,46 @@ TOON reduces output by ~40% vs JSON. Lossless roundtrip. Based on `@toon-format/
|
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
114
|
# JSON input (as before)
|
|
115
|
-
mythik patch task-manager --from-file patch.json --author <agent>
|
|
115
|
+
mythik patch task-manager --from-file patch.json --author <agent>
|
|
116
116
|
|
|
117
117
|
# TOON input (autodetected)
|
|
118
|
-
mythik patch task-manager --from-file patch.toon --author <agent>
|
|
118
|
+
mythik patch task-manager --from-file patch.toon --author <agent>
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
### Workflow: Manifest → Elements → Patch
|
|
122
122
|
|
|
123
123
|
1. **`mythik manifest <screen>`** — see the structure, decide what to modify
|
|
124
124
|
2. **`mythik elements <screen> <ids>`** — inspect specific elements you need to change
|
|
125
|
-
3. **`mythik patch <screen> --from-file patch.json --author <agent>`** - apply a surgical, versioned change
|
|
126
|
-
4. **`mythik validate <screen>`** — validate the stored result
|
|
127
|
-
5. **`mythik manifest <screen>`** — verify the changed structure
|
|
125
|
+
3. **`mythik patch <screen> --from-file patch.json --author <agent>`** - apply a surgical, versioned change
|
|
126
|
+
4. **`mythik validate <screen>`** — validate the stored result
|
|
127
|
+
5. **`mythik manifest <screen>`** — verify the changed structure
|
|
128
128
|
|
|
129
129
|
This is the required default loop for AI agents editing an existing spec. Do not begin a small change by pulling the full spec and rewriting it. `manifest` gives the structural map, `elements` gives the exact JSON for the target nodes, and `patch --from-file` keeps the write validated, versionable, and reviewable. Use `pull` for backup/migration/review and `push` for new specs or deliberate full replacement only.
|
|
130
130
|
|
|
131
|
+
### Mythik Sentinel - Agent Protocol Guardrail
|
|
132
|
+
|
|
133
|
+
Mythik Sentinel is built into the CLI so a fresh AI agent is not left
|
|
134
|
+
alone with generic command habits. It is advisory and best-effort: it
|
|
135
|
+
does not change the real command exit code, and it never stores specs,
|
|
136
|
+
patches, URLs, credentials, state values, or Reveal context.
|
|
137
|
+
|
|
138
|
+
Sentinel watches command intent per project. On first CLI use, it asks
|
|
139
|
+
the agent to run `mythik agent init codex|claude|all`. If it sees
|
|
140
|
+
repeated full replacement intent (`push --replace` or
|
|
141
|
+
`push --from-dir --replace`) with little/no `patch` usage, it warns the
|
|
142
|
+
agent back to `manifest -> elements -> patch --from-file --author ->
|
|
143
|
+
validate -> verify`.
|
|
144
|
+
|
|
145
|
+
Machine-readable output stays machine-readable. JSON object outputs may
|
|
146
|
+
receive `protocol.warnings`. TOON output and other machine formats are
|
|
147
|
+
not wrapped with human text. Use `MYTHIK_SENTINEL=off` only for
|
|
148
|
+
exceptional automation that needs to suppress advisory warnings.
|
|
149
|
+
|
|
150
|
+
`push --replace` also has no-diff protection. If the submitted document
|
|
151
|
+
is identical to the stored document, Mythik skips the write instead of
|
|
152
|
+
creating a new version. JSON output reports `skipped: true` and
|
|
153
|
+
`skipReason: "no-diff"`.
|
|
154
|
+
|
|
131
155
|
### Mythik Reveal — Live Runtime Context for AI Agents
|
|
132
156
|
|
|
133
157
|
`mythik reveal` lets a running Mythik app expose its live contract,
|
|
@@ -214,15 +238,15 @@ Security rules:
|
|
|
214
238
|
### Full Spec Lifecycle
|
|
215
239
|
|
|
216
240
|
```bash
|
|
217
|
-
Create: mythik push <id> --from-file spec.json --author <agent>
|
|
218
|
-
Read: mythik manifest <id> / mythik elements <id> ids / mythik pull <id>
|
|
219
|
-
Modify: mythik patch <id> --from-file patch.json --author <agent>
|
|
220
|
-
Validate: mythik validate <id>
|
|
221
|
-
Delete: mythik delete <id> --confirm
|
|
222
|
-
Backup: mythik pull <id> > backup.json
|
|
223
|
-
Restore: mythik push <id> --from-file backup.json --replace --author <agent>
|
|
224
|
-
Migrate: mythik push <id> --from-file exported.json --author <agent> --store B
|
|
225
|
-
Tokens: mythik tokens --dna '{"primary":"#0D9488"}' --json
|
|
241
|
+
Create: mythik push <id> --from-file spec.json --author <agent>
|
|
242
|
+
Read: mythik manifest <id> / mythik elements <id> ids / mythik pull <id>
|
|
243
|
+
Modify: mythik patch <id> --from-file patch.json --author <agent>
|
|
244
|
+
Validate: mythik validate <id>
|
|
245
|
+
Delete: mythik delete <id> --confirm
|
|
246
|
+
Backup: mythik pull <id> > backup.json
|
|
247
|
+
Restore: mythik push <id> --from-file backup.json --replace --author <agent>
|
|
248
|
+
Migrate: mythik push <id> --from-file exported.json --author <agent> --store B
|
|
249
|
+
Tokens: mythik tokens --dna '{"primary":"#0D9488"}' --json
|
|
226
250
|
```
|
|
227
251
|
|
|
228
252
|
### Push — Create New Screens
|
|
@@ -340,7 +364,7 @@ Every screen is a JSON Spec with a `root` ID, a flat `elements` map, and optiona
|
|
|
340
364
|
| `style` | object | CSS styles (can contain expressions) |
|
|
341
365
|
| `visible` | boolean or condition | Show/hide condition |
|
|
342
366
|
| `permission` | object | Role-based access: `{ visible, editable, readonly }` |
|
|
343
|
-
| `repeat` | object | Iterate over array: `{ statePath, key }` or `{ source: expression, key }` |
|
|
367
|
+
| `repeat` | object | Iterate over array: `{ statePath, key }` or `{ source: expression, key }`; optional `layout` controls item row direction/gap/wrap |
|
|
344
368
|
| `on` | object | Event handlers: `{ press: action, change: action }` |
|
|
345
369
|
| `hover` | object | Style overrides when pointer enters (rendered via Motion) |
|
|
346
370
|
| `active` | object | Style overrides when element is pressed (rendered via Motion) |
|
|
@@ -680,7 +704,7 @@ Each primitive accepts `style` (CSS object), `visible` (condition), and `permiss
|
|
|
680
704
|
|
|
681
705
|
### Icon Primitive
|
|
682
706
|
|
|
683
|
-
The `icon` primitive renders icons from a connected icon library. By default it's a placeholder — apps connect a library via `plugins.
|
|
707
|
+
The `icon` primitive renders icons from a connected icon library. By default it's a placeholder — apps connect a library once via `plugins.setIconRenderer(Component)`. Built-in icons, table action icons, toast icons, and React Native icon consumers use that same registration.
|
|
684
708
|
|
|
685
709
|
```json
|
|
686
710
|
{ "type": "icon", "props": { "name": "pencil-simple", "size": 16, "weight": "bold", "color": "#666" } }
|
|
@@ -1322,6 +1346,18 @@ Use `source` for filtered/paginated lists:
|
|
|
1322
1346
|
|
|
1323
1347
|
Inside repeated elements, use `$item` and `$index` to access the current item's data. These work in `props`, `style`, `visible`, and `on` (event params).
|
|
1324
1348
|
|
|
1349
|
+
Use `repeat.layout` when the repeated items should render as a horizontal or wrapping row:
|
|
1350
|
+
|
|
1351
|
+
```json
|
|
1352
|
+
"repeat": {
|
|
1353
|
+
"source": { "$state": "/filters" },
|
|
1354
|
+
"key": "id",
|
|
1355
|
+
"layout": { "direction": "horizontal", "gap": 8, "wrap": true }
|
|
1356
|
+
}
|
|
1357
|
+
```
|
|
1358
|
+
|
|
1359
|
+
Grouped repeats keep group headers/footers vertical and apply `repeat.layout` only to each group's item row.
|
|
1360
|
+
|
|
1325
1361
|
### Grouped Repeat (`groupBy`)
|
|
1326
1362
|
|
|
1327
1363
|
Two modes — auto-detected:
|
|
@@ -2033,7 +2069,7 @@ Reference tokens or write custom values:
|
|
|
2033
2069
|
37. **Device context is auto-tracked** — viewport, platform, orientation, OS color scheme write to `/ui/device/*` automatically. Use `$breakpoint` for responsive values, `$platform` for cross-platform branching, `$state` for orientation detection
|
|
2034
2070
|
38. **Use `forms` for coordinated validation** — form-level `isValid`, cross-field rules, submit gating. Use inline `checks` on inputs for standalone fields without form coordination
|
|
2035
2071
|
39. **Use `$auth` for user data, not `$state`** — `{ "$auth": "email" }` is safer (whitelisted fields only) and more stable than `{ "$state": "/auth/user/email" }`. `$auth` blocks access to tokens/passwords even if somehow in state
|
|
2036
|
-
40. **Auth headers are auto-injected** — specs don't need to specify auth headers in `fetch`/`submitForm`.
|
|
2072
|
+
40. **Auth headers are auto-injected** — specs don't need to specify auth headers in `fetch`/`submitForm`. With `MythikApp apiBaseUrl`, framework-owned relative URLs inherit auth for that exact origin when `authDomains` is omitted or empty. Providing `authDomains` disables that automatic `apiBaseUrl` origin allowlist; list every trusted absolute host explicitly.
|
|
2037
2073
|
41. **Login screen is a normal spec** — build login forms with regular primitives (input, button). The `login` action connects to the auth provider. No special components needed. Use `$bindState: "/login/username"` and `"/login/password"` for form fields. The `login` action receives `{ email: "$state /login/username", password: "$state /login/password" }`
|
|
2038
2074
|
42. **Never trust client auth as security** — `AppAuthConfig` is UX routing (hide screens by role), not server-side security. Always validate tokens on the backend
|
|
2039
2075
|
43. **Use `roleAccess` for centralized access control** — when defined, it's the sole source of truth. Roles not listed get zero access. `ScreenDefinition.roles` is only used when `roleAccess` is absent
|
|
@@ -2052,9 +2088,9 @@ Reference tokens or write custom values:
|
|
|
2052
2088
|
56. **Auto-skeleton activates when spec has `fetch` in initialActions + loading + empty data** — zero config needed. Set `skeleton: false` on elements that show static content. Set `autoSkeleton={false}` on MythikRenderer to disable entirely
|
|
2053
2089
|
57. **Use `export` action for data downloads, not custom fetch** — format `"csv"` is always available (built-in). For `"xlsx"` or `"pdf"`, register an ExportAdapter via `exportAdapters` prop on MythikRenderer
|
|
2054
2090
|
58. **Export columns support formatting** — `format: "currency"` with `formatOptions: { currency: "USD", locale: "en-US", decimals: 2 }`. Same Intl formatters as `$format` expression handler
|
|
2055
|
-
59. **Use `variant` prop for consistent
|
|
2056
|
-
60. **Element-level style/hover/active overrides variant** — variant is always the base. For one-off customizations, add explicit style/hover on the element. For reusable customizations, define a new variant
|
|
2057
|
-
61. **Use `$path` references in variant definitions** — `$colors.primary` resolves against active tokens so dark mode works automatically.
|
|
2091
|
+
59. **Use `variant` prop for consistent primitive styling** — don't copy style objects between elements. Define variants in `tokens.components.{type}.{variant}` and reference with `props.variant`. Variants are for visual slots (`style`, `hover`, `active`, `focus`, `transition`, `animations`), not arbitrary primitive props.
|
|
2092
|
+
60. **Element-level style/hover/active overrides variant** — variant is always the base. For one-off customizations, add explicit style/hover on the element. For reusable customizations, define a new variant. For reusable prop-bearing patterns such as table `headerStyle`/`rowStyle`, `columns`, `onRowClick`, or composed children, use `templates` or Layer 3 custom elements instead of copying props into every table/chip.
|
|
2093
|
+
61. **Use `$path` references in variant definitions** — `$colors.primary` resolves against active tokens so dark mode works automatically. Variant definitions do not evaluate render-context expressions such as `$state`, `$item`, or `$prop`; keep state/item-specific active styling on the element or move the composition to a template/custom element.
|
|
2058
2094
|
62. **AppSpec patches use `/layout/elements/` not `/elements/`** — Screen spec elements are at `/elements/{id}`. AppSpec layout elements are at `/layout/elements/{id}`. Use dot-notation with `mythik elements` for inspecting non-element sections (tokens, screens, etc.)
|
|
2059
2095
|
63. **AppSpec is filtered without Bearer token** — `GET /api/app/:id` strips `roleAccess` and `protectedScreens` from the response when no valid Bearer token is present. This prevents information disclosure of the authorization model. With a valid Bearer, the full AppSpec is returned. The endpoint never returns 401 — only the payload changes
|
|
2060
2096
|
64. **CLI warns on unknown prop names** — `mythik push` and `mythik validate` check prop names against known schemas for all 38 primitives. Unknown props generate warnings (not errors) with Levenshtein suggestions: `⚠ unknown prop "inputType" for type "input" — did you mean "type"?`. Warnings don't block saves
|
|
@@ -2085,13 +2121,13 @@ Reference tokens or write custom values:
|
|
|
2085
2121
|
89. **Lazy bootstrap for existing specs** — first versioned save on an existing spec with no history automatically creates v1 (snapshot of current spec), then saves the change as v2. No migration script needed. Specs without history continue working via base `SpecStore.load()`
|
|
2086
2122
|
90. **Use `navigateScreen` and `goBackScreen` in specs** — `navigateScreen` and `goBackScreen` are registered by MythikApp and call the AppEngine directly. The built-in `navigate` and `goBack` only set state intents. Always use `navigateScreen`/`goBackScreen` in specs for navigation that works. Example: `{ "action": "goBackScreen" }` goes back to the previous screen in the navigation history, regardless of which screen navigated to the current one
|
|
2087
2123
|
91. **CLI `--table` flag overrides the current spec table** — all commands accept `--table <name>` to read/write from a different base table. Use `--table api_specs` to operate on api-specs. The flag overrides the base table for Supabase, SQL Server, PostgreSQL, MySQL, and SQLite stores. Version and environment tables are configured separately with `MYTHIK_VERSIONS_TABLE`, `MYTHIK_ENVIRONMENTS_TABLE`, or the equivalent `.mythikrc` SQL settings.
|
|
2088
|
-
92. **`push` and `patch` require explicit write intent** — persisted writes should use `--author <name>` so the resolved versioned store records a version through `VersionedSpecStore.saveVersion()`. Existing specs require `--replace` for full replacement. Use `--allow-unversioned` only for intentionally unversioned stores such as file-store smoke tests. The version includes author, source type (`push`/`patch`), and optional `--description`. Example: `mythik patch screen-id --from-file patch.json --author alice --description "Fixed layout"`
|
|
2124
|
+
92. **`push` and `patch` require explicit write intent** — persisted writes should use `--author <name>` so the resolved versioned store records a version through `VersionedSpecStore.saveVersion()`. Existing specs require `--replace` for full replacement. Use `--allow-unversioned` only for intentionally unversioned stores such as file-store smoke tests. The version includes author, source type (`push`/`patch`), and optional `--description`. Example: `mythik patch screen-id --from-file patch.json --author alice --description "Fixed layout"`
|
|
2089
2125
|
93. **`mythik history` shows inline diffs** — each version in the history output shows the actual changes (before/after values), not just a summary. Uses `computeStructuralDiff` between consecutive versions. Example output: `~ element "btn" prop content: "Send" → "Submit"`
|
|
2090
2126
|
95. **`ai-context.md` is the AI-optimized spec reference** — compressed from this reference-doc (1145 lines vs 2658). Use ai-context.md for spec generation, reference-doc for full human reference. Validated via agent-based testing with progressive difficulty levels (L1-L4). Test scenarios in `../ai-context-test-scenarios.md`, results in `../ai-context-test-results.md` (framework-dev, not part of consumer publish surface)
|
|
2091
2127
|
|
|
2092
2128
|
94. **Generic SQL versioned stores are available** — `resolveVersionedStore` supports `sqlserver`, `postgres`, `mysql`, and `sqlite` store types. It creates a driver-backed `SqlVersionedSpecStore` (specs + version history) plus `SqlEnvironmentStore` (environment pointers). Requires `screens`, `screen_versions`, and `screen_environments`; initialize with `mythik init-store` or apply the DDL from `mythik init-store --dry-run`.
|
|
2093
2129
|
96. **SupabaseVersionedSpecStore available** — `resolveVersionedStore` supports `supabase` store type. Uses PostgREST REST API (no `@supabase/supabase-js` dependency). Same snapshot+patches pattern as SqlServer. Environment upsert uses `on_conflict=screen_id,environment` for PostgREST compatibility. Requires `screen_versions` and `screen_environments` tables created in Supabase dashboard
|
|
2094
|
-
97. **`variant` is a universal prop** — any primitive can use `variant` when component variants are defined in `tokens.components.{type}.{variant}`. The validator accepts `variant` on all primitives (via `COMMON_PROPS`). The render engine resolves variants before passing props to the primitive
|
|
2130
|
+
97. **`variant` is a universal prop** — any primitive can use `variant` when component variants are defined in `tokens.components.{type}.{variant}`. The validator accepts `variant` on all primitives (via `COMMON_PROPS`). The render engine resolves variants before passing props to the primitive. Put `variant` inside `props`, and use variants as the first-line reuse mechanism before duplicating visual style blocks.
|
|
2095
2131
|
98. **Use DNA seeds for app identity** — define `tokens.dna` in AppSpec with 1-8 seed values. The framework derives all visual tokens (colors via OKLCH tonal palette, shape, typography, spacing, elevation, motion, opacity) plus auto dark mode. No manual color palette or radius scale needed — DNA generates it from `{ "primary": "#0D9488" }`
|
|
2096
2132
|
99. **Three-layer token resolution** — Framework DEFAULTS (always present) → DNA derivation (if `dna` seed exists) → Manual overrides (explicit `tokens.*` values always win). Specs without tokens use defaults. Specs with only DNA get full derived identity. Specs with DNA + overrides get derived base with surgical customization
|
|
2097
2133
|
100. **`$token` auto-converts elevation to CSS** — `{ "$token": "elevation.md" }` returns a CSS `boxShadow` string on web (e.g., `"0px 4px 12px rgba(0,0,0,0.15)"`). On RN, primitives handle elevation internally via native shadow props. No manual conversion needed
|
|
@@ -2104,7 +2140,7 @@ Reference tokens or write custom values:
|
|
|
2104
2140
|
107. **`Element.key` forces remount on value change** — Add `key` to any element with a dynamic expression (e.g., `{ "$template": "preview-${/internal/tokenVersion}" }`). When the resolved value changes, React unmounts and remounts the element, re-triggering mount animations. Used by DNA Playground to re-animate preview on Apply DNA
|
|
2105
2141
|
108. **Input supports `type: "color"`** — Renders native OS color picker. Use with `$bindState` for interactive color selection in specs
|
|
2106
2142
|
109. **Slider label is display-only** — The slider primitive renders the `label` prop as-is without appending the current value. Use `$template` in the label to include the value if desired (e.g., `"label": { "$template": "Roundness: ${/dna/roundness}%" }`)
|
|
2107
|
-
110. **`--author` is the normal persisted-write path** — `mythik push` and `mythik patch` with `--author ai-agent` use `VersionedSpecStore` when available, writing to both `screens` and `screen_versions` and enabling `history`, `diff`, and `rollback` commands. Without `--author`, persisted writes are rejected unless `--allow-unversioned` is explicit. Always use `--author` during development.
|
|
2143
|
+
110. **`--author` is the normal persisted-write path** — `mythik push` and `mythik patch` with `--author ai-agent` use `VersionedSpecStore` when available, writing to both `screens` and `screen_versions` and enabling `history`, `diff`, and `rollback` commands. Without `--author`, persisted writes are rejected unless `--allow-unversioned` is explicit. Always use `--author` during development.
|
|
2108
2144
|
111. **Identity System — `tokens.identity` controls visual identity beyond DNA** — DNA controls continuous/color values. Identity controls categorical dimensions: `surface` (how containers render), `radiusPattern` (corner shape), `typographyHierarchy` (heading scale), `labelStyle` (label formatting), `textDecoration` (heading decoration), `depth` (shadow intensity 0-1), `shadowAngle` (shadow direction 0-360°), `colorScheme` (light/dark/colored polarity), `colorWeight` (where color appears), `accentApplication` (where accent appears). Set via `tokens.identity` in AppSpec or screen Spec. Lint validates deep identity enum/range values; for example use `colorScheme: "light-surface"`, not `"light"`
|
|
2109
2145
|
112. **Surface Treatment — 6 types transform all containers** — `identity.surface`: `elevated` (shadow+border, material), `flat` (color blocks only, no borders/shadows), `outlined` (borders only, transparent bg, Linear-like), `glass` (backdrop-filter blur, semi-transparent), `bold` (thick 2-3px borders, brutalist), `neo` (neumorphic inset+outset shadows). Every input, button, card, modal, select, textarea, checkbox, accordion, table adapts automatically
|
|
2110
2146
|
113. **Surface styles are explicit — every property set, no implicit values** — All 6 surface types define `border` and `boxShadow` explicitly for every component category. Properties are `'none'` when not used, never omitted. This prevents browser defaults from showing (e.g., native button borders in flat mode)
|
|
@@ -2147,7 +2183,7 @@ Reference tokens or write custom values:
|
|
|
2147
2183
|
150. **Gradient interpolation in OKLCH** — All gradient text and gradient buttons use `linear-gradient(in oklch, ...)` for vibrant transitions. sRGB interpolation crosses through desaturated midpoints (purple→gold becomes muddy brown); OKLCH maintains saturation through the hue arc. Graceful degradation on older browsers
|
|
2148
2184
|
151. **Gradient modes: vibrant, soft, muted** — `identity.gradients.text`, `identity.gradients.buttons`, and `identity.gradients.cards` accept `boolean | 'vibrant' | 'soft' | 'muted'`. For text and buttons: Vibrant = OKLCH primary→accent. Soft = OKLCH primaryLight→accentLight (subtle). Muted = sRGB primary→accent (desaturated center, luxury/editorial aesthetic). For cards: Vibrant = 33% primary alpha (dramatic). Muted = 20% primary alpha (balanced default). Soft = 8% primary alpha (subtle kiss). `true` maps to vibrant for text/buttons, muted for cards
|
|
2149
2185
|
152. **Explicit accent hex preserved as-is** — When `dna.accent` is set explicitly, `deriveDna` uses the exact hex for `colors.accent` instead of passing through `generateTonalPalette` step 60. The palette is still generated (for `accentLight`), but the primary accent color is the user's exact choice
|
|
2150
|
-
153. **`setIconRenderer` replaces `overridePrimitive` for icons** — `plugins.setIconRenderer(Component)` registers a custom icon renderer. The framework's `icon.tsx` handles identity wrapping (container, weight default) while the registered component renders the actual icon. `overridePrimitive('icon', ...)` still works but bypasses identity features
|
|
2186
|
+
153. **`setIconRenderer` replaces `overridePrimitive` for icons** — `plugins.setIconRenderer(Component)` registers a custom icon renderer. The framework's `icon.tsx` handles identity wrapping (container, weight default) while the registered component renders the actual icon. Table action icons, toast icons, and React Native icon consumers use the same registration. `overridePrimitive('icon', ...)` still works for full primitive replacement but bypasses identity features
|
|
2151
2187
|
154. **Do not emit Box `backgroundBlobs`** — Box `backgroundBlobs` and legacy per-element blob rendering are not part of the public primitive contract. App-level background lives exclusively at `tokens.identity.background` (rule 147) and mounts at MythikRenderer via `<BackgroundStack>`. Box is a pure surface-styled wrapper; primitives do not rely on `dangerouslySetInnerHTML` for keyframe injection.
|
|
2152
2188
|
155. **Do not emit `$token: "backgroundCSS"`** — `$token: "backgroundCSS"` does not resolve. For preset-aware app backgrounds, set `tokens.identity.background` as a LayerBackground (rule 147) — presets update that field directly so the root `<BackgroundStack>` re-resolves on preset switch. No token alias indirection needed.
|
|
2153
2189
|
156. **Accordion `badge` prop** — `accordion` accepts optional `badge` prop (`string | number | boolean`). Renders as: solid 8px primary-colored dot for `true`, pill with text/number for string/number values. Hidden when `false`, `0`, `undefined`, or `''`. Use with `$state` for reactive indicators: `"badge": { "$state": "/modified/mySection" }`
|
|
@@ -2192,7 +2228,7 @@ Reference tokens or write custom values:
|
|
|
2192
2228
|
}
|
|
2193
2229
|
```
|
|
2194
2230
|
|
|
2195
|
-
**`authDomains` matcher behavior:**
|
|
2231
|
+
**`apiBaseUrl` + `authDomains` matcher behavior:** when a React host passes `apiBaseUrl`, framework-owned relative runtime URLs such as `/api/orders` resolve against that base before URL guards, auth interceptors, and fetch execution. If auth is enabled and `authDomains` is omitted or empty, the exact origin of `apiBaseUrl` (`protocol + host + port`) becomes the default auth target. Same-host services on other ports do not inherit that token. If `authDomains` is provided, the automatic `apiBaseUrl` origin allowlist is disabled; list every trusted absolute host explicitly. The matcher compares hostname only, strips ports, and supports exact/subdomain matching. See `ai-context-runtime-semantics.md § 4.1`.
|
|
2196
2232
|
|
|
2197
2233
|
### `$auth` Expression
|
|
2198
2234
|
|
|
@@ -2320,7 +2356,7 @@ The `statePolicy: "reset"` is what clears `/screens/login` on every navigation t
|
|
|
2320
2356
|
|
|
2321
2357
|
- Tokens NEVER exist in the state store — only in engine closure
|
|
2322
2358
|
- `$auth` blocks token/password fields via whitelist
|
|
2323
|
-
- Auth headers only injected for `authDomains` URLs
|
|
2359
|
+
- Auth headers only injected for the host `apiBaseUrl` exact origin or explicit `authDomains` URLs
|
|
2324
2360
|
- Credentials cleared from state after login (success AND failure)
|
|
2325
2361
|
- Refresh mutex: max 1 concurrent refresh (anti-stampede)
|
|
2326
2362
|
- Login rate limit: 5 attempts/min with exponential backoff
|
|
@@ -2348,7 +2384,7 @@ The framework uses a scoped fetch wrapper (NOT `globalThis.fetch`). All `fetch`
|
|
|
2348
2384
|
|
|
2349
2385
|
| Interceptor | Config | Behavior |
|
|
2350
2386
|
|-------------|--------|----------|
|
|
2351
|
-
| **Auth** | Auto when auth configured | Injects Bearer token for `authDomains` URLs. Triggers refresh+retry on 401. |
|
|
2387
|
+
| **Auth** | Auto when auth configured | Injects Bearer token for the host `apiBaseUrl` exact origin or explicit `authDomains` URLs. Triggers refresh+retry on 401. |
|
|
2352
2388
|
| **Logging** | `"logging": true` | Logs request method/URL and response status. Redacts sensitive query params (token, password, key). |
|
|
2353
2389
|
| **Timeout** | `"timeout": { "ms": 15000 }` | Aborts request after configured milliseconds. Uses AbortController. |
|
|
2354
2390
|
| **Retry** | `"retryOnError": { ... }` | Retries on transient server errors (502, 503, 504) with exponential backoff. |
|
|
@@ -3153,7 +3189,7 @@ The current background and motion stack combines app-level `LayerBackground`, an
|
|
|
3153
3189
|
|
|
3154
3190
|
211. **`useShapeAnimations(ref, animations, options)` — Layer 3 web runner** — Exported from `mythik-react` via `packages/react/src/animation/useShapeAnimations.ts`. React hook for SVG-child animations (`<path>`/`<circle>`/`<rect>`/`<g>`…). Consumes the same `ElementAnimations` contract as `useElementAnimations` but narrowed to the `ambient` trigger ONLY; shape children have no hover/focus/active contract and no distinct mount ceremony. Attaches CSS animations via `el.style.animation` (surgical, preserves other inline styles); keyframes register once through the CSSOM singleton (zero `dangerouslySetInnerHTML`) and dedupe by hash so multiple shape instances with the same recipe share one CSS rule. Dev mode warns when non-ambient triggers are passed. Production silently ignores them. `options.recipes` SHOULD be stable for useMemo performance.
|
|
3155
3191
|
|
|
3156
|
-
212. **`useShapeAnimations(animations, options)` — Layer 3 RN runner** — Implemented inside `mythik-react-native` at `packages/react-native/src/animation/useShapeAnimations.ts` for the native blob/background renderer. It is not exported from the package root as a standalone public hook. Reanimated parity of rule 211: returns `{ animatedProps }` that the renderer spreads onto `Animated.createAnimatedComponent(Path)` from `react-native-svg`. Uses the `HARD_PER_TRIGGER` (=6) fixed-pool `useSharedValue` pattern (`useSharedValueArray` helper) so React Hook count stays stable. Reuses `composeRNStyle(contributions, interpolate, interpolateColor)` shared with `useElementAnimations` — single composition pipeline for View-style and animated SVG props. Relies on `react-native-svg` v13+ auto-translating the transform array into SVG `transform="..."` strings. Same dev-mode non-ambient-trigger warning as the web hook.
|
|
3192
|
+
212. **`useShapeAnimations(animations, options)` — Layer 3 RN runner** — Implemented inside `mythik-react-native` at `packages/react-native/src/animation/useShapeAnimations.ts` for the native blob/background renderer. It is not exported from the package root as a standalone public hook. Reanimated parity of rule 211: returns `{ animatedProps }` that the renderer spreads onto `Animated.createAnimatedComponent(Path)` from `react-native-svg`. Uses the `HARD_PER_TRIGGER` (=6) fixed-pool `useSharedValue` pattern (`useSharedValueArray` helper) so React Hook count stays stable. Reuses `composeRNStyle(contributions, interpolate, interpolateColor)` shared with `useElementAnimations` — single composition pipeline for View-style and animated SVG props. Relies on `react-native-svg` v13+ auto-translating the transform array into SVG `transform="..."` strings. Same dev-mode non-ambient-trigger warning as the web hook.
|
|
3157
3193
|
|
|
3158
3194
|
213. **Cross-platform Layer 3 parity pins** — `buildCSSKeyframes` (web) and `buildReanimatedSpec` (RN) interpret the same resolved `AnimationSpec` identically on load-bearing invariants: duration agreement (ms count matches regardless of input form `'28s'`/`'28000'`), keyframe stop count (web `%` markers match RN `inputRange` length), direction semantic (`'alternate'` token ⇔ `timing.reverse=true`), iterations `'infinite'`/numeric count, animated-prop enumeration (`translateX/Y`/`rotateDeg`/`scale`).
|
|
3159
3195
|
|
|
@@ -3229,7 +3265,7 @@ The current background and motion stack combines app-level `LayerBackground`, an
|
|
|
3229
3265
|
|
|
3230
3266
|
247. **`derive` and `dataSources` are processed at runtime per spec mount** (v0.1.0). When `spec.derive` is present, the framework instantiates a `DeriveEngine`, evaluates all derive paths in topological order at mount, and re-evaluates dirty paths reactively on state changes. Derive paths are protected: setState targeting a derive path errors at validate time and runtime. When `spec.dataSources` is present, the framework instantiates a `DataSourcesEngine`, performs initial fetches (deferred to reactive resolution when URL template deps are undefined), and re-fetches reactively when dependencies change. The action `refreshDataSource` (params: `{ id: string }`) is automatically registered for any spec with dataSources. URL templating requires the explicit `{ $template: '...' }` form — plain strings with `${...}` are NOT substituted (validator catches at load). See `ai-context-runtime-semantics.md` for lifecycle, ordering, error degradation, and state protection details.
|
|
3231
3267
|
|
|
3232
|
-
248. **CLI is the only approved path for spec writes** (v0.1.0). Three approved forms: (a) **Shell** - `mythik push <id> --from-file spec.json --author <name>` / `mythik patch <id> --from-file patch.json --author <name>` (or intentional stdin via `--from-file -` / pipe without `--from-file` plus `--author`); (b) **Bulk** - `mythik push --from-dir ./specs/ --author <name>` (sequential, continue-on-error, no rollback; partial state on failure recovers by fixing failures and re-running the same command); (c) **Programmatic** - `import { runPush, runPatch } from 'mythik-cli/api'` for IDE tooling, test harnesses, CI scripts. NEVER call `SpecStore.save()` directly from application code. It is an internal persistence primitive marked `@internal`; validation happens at the CLI / engine tier. Bypassing this path skips validation and can produce runtime errors visible only at render time. `mythik patch --from-file <path>` is preferred over inline JSON for any patch containing `$state`, `$template`, `$auth`, or `$row` references (PowerShell expands `$<word>` in double-quoted strings). Existing full-spec replacement requires `--replace`; intentionally unversioned writes require `--allow-unversioned`.
|
|
3268
|
+
248. **CLI is the only approved path for spec writes** (v0.1.0). Three approved forms: (a) **Shell** - `mythik push <id> --from-file spec.json --author <name>` / `mythik patch <id> --from-file patch.json --author <name>` (or intentional stdin via `--from-file -` / pipe without `--from-file` plus `--author`); (b) **Bulk** - `mythik push --from-dir ./specs/ --author <name>` (sequential, continue-on-error, no rollback; partial state on failure recovers by fixing failures and re-running the same command); (c) **Programmatic** - `import { runPush, runPatch } from 'mythik-cli/api'` for IDE tooling, test harnesses, CI scripts. NEVER call `SpecStore.save()` directly from application code. It is an internal persistence primitive marked `@internal`; validation happens at the CLI / engine tier. Bypassing this path skips validation and can produce runtime errors visible only at render time. `mythik patch --from-file <path>` is preferred over inline JSON for any patch containing `$state`, `$template`, `$auth`, or `$row` references (PowerShell expands `$<word>` in double-quoted strings). Existing full-spec replacement requires `--replace`; intentionally unversioned writes require `--allow-unversioned`.
|
|
3233
3269
|
|
|
3234
3270
|
249. **`mythik lint` detects known anti-patterns in specs and consumer code** (v0.1.0).
|
|
3235
3271
|
|
|
@@ -3244,7 +3280,7 @@ A new CLI command + programmatic API:
|
|
|
3244
3280
|
- `spec-row-literal` (warning) — `$row` is not an expression handler; use `$state: '/ui/selectedRow/<key>'`. Validator-resident in `spec-validator.ts` (also surfaces during `mythik push` and `mythik validate`).
|
|
3245
3281
|
- `spec-crud-id-collision` (error) — `endpoint.path` ending `/:id` combined with `crud: {}` produces `/path/:id/:id`. Strip trailing `/:id`. Walks the object-shaped `endpoints: Record<string, EndpointConfig>`; emits JSON Pointer paths `/endpoints/<name>/path`.
|
|
3246
3282
|
- `spec-auth-domains-port` (warning) — `auth.authDomains[i]` containing `:port` strips the port silently (matcher uses hostname-only via `URL.hostname`). Walks the `string[]` shape; emits JSON Pointer paths `/auth/authDomains/<index>`.
|
|
3247
|
-
- `code-store-save-bypass` (error) — calling `*store*.save()` outside `packages/core/` and `packages/cli/` bypasses validation. Use `runPush` from `mythik-cli/api` with `author` or `mythik push --from-file ... --author <name>`. **Known scope**: matches `<Identifier>.save()` callees only (e.g. `myStore.save(...)`). Does NOT detect `this.store.save()`, `<obj>.<store>.save()`, or `(await getStore()).save()` patterns — these slip through the AST scanner. Generation-level guidance in `ai-context.md` (anti-patterns section) covers all variants; the lint rule is one layer of defense-in-depth, not a complete catch. Widening the scanner to handle `PropertyAccessExpression` callees is tracked as a v0.2+ candidate if real consumer code shows these patterns slipping through generation guidance.
|
|
3283
|
+
- `code-store-save-bypass` (error) — calling `*store*.save()` outside `packages/core/` and `packages/cli/` bypasses validation. Use `runPush` from `mythik-cli/api` with `author` or `mythik push --from-file ... --author <name>`. **Known scope**: matches `<Identifier>.save()` callees only (e.g. `myStore.save(...)`). Does NOT detect `this.store.save()`, `<obj>.<store>.save()`, or `(await getStore()).save()` patterns — these slip through the AST scanner. Generation-level guidance in `ai-context.md` (anti-patterns section) covers all variants; the lint rule is one layer of defense-in-depth, not a complete catch. Widening the scanner to handle `PropertyAccessExpression` callees is tracked as a v0.2+ candidate if real consumer code shows these patterns slipping through generation guidance.
|
|
3248
3284
|
|
|
3249
3285
|
**Code rules require TypeScript ^5.0.0 as peerDependency** (optional). If not installed, code rules emit one warning finding `lint-meta-no-typescript` (severity matches `LintSeverity = 'error' | 'warning'`) and skip cleanly. Spec rules run independently.
|
|
3250
3286
|
|
|
@@ -3256,7 +3292,7 @@ See `ai-context.md` for spec-gen anti-patterns the AI must NOT generate.
|
|
|
3256
3292
|
|
|
3257
3293
|
250. **Storage tables are initialized explicitly, never silently at runtime** (v0.1.0). SQL-backed stores operate against three tables the consumer database must already have: `screens` (base, required), `screen_versions` (version history), and `screen_environments` (environment promotions). Use `mythik init-store --dialect <sqlserver|postgres|mysql|sqlite> --dry-run` to inspect canonical idempotent DDL, initialize a local SQLite file with `mythik init-store --dialect sqlite --target ./mythik.db`, or initialize a reachable SQL Server store with explicit `--server`, `--database`, `--user`, `--password`, `--encrypt`, and `--trust-server-certificate` flags. The same schema is described in `ai-context.md § Storage Setup`. Runtime reads/writes do not create missing tables. Production deployment scripts should verify required columns after apply.
|
|
3258
3294
|
251. **`security.exposeErrors` controls render error detail** (v0.1.0). Default is `true`; set `createMythik({ security: { exposeErrors: false } })` for production-like hosts that must avoid leaking error messages/stacks. `_error` render nodes write diagnostics to `/ui/renderErrors` only when exposure is enabled. Primitive/component exceptions are caught by `MythikRenderer`'s error boundary: development + exposed mode shows an overlay with message and component stack; production or `exposeErrors: false` shows a neutral placeholder. The overlay resets when the spec changes so a corrected spec can recover without remounting the host.
|
|
3259
|
-
252. **Icon packs register through `plugins.setIconRenderer`** (v0.1.0). Mythik does not bundle Phosphor/Lucide/etc. Register one host-level renderer from `MythikApp.onPlugins`; the built-in `icon` primitive keeps identity behavior and calls the renderer with `{ name, size, weight, color, style }`. If the placeholder circle renders, verify `onPlugins` registered the renderer and the consumer is not validating against stale tarballs or source aliases.
|
|
3295
|
+
252. **Icon packs register through `plugins.setIconRenderer`** (v0.1.0). Mythik does not bundle Phosphor/Lucide/etc. Register one host-level renderer from `MythikApp.onPlugins`; the built-in `icon` primitive, table action icons, toast icons, and React Native icon consumers use that same registration. The built-in `icon` primitive keeps identity behavior and calls the renderer with `{ name, size, weight, color, style }`. If the placeholder circle renders, verify `onPlugins` registered the renderer and the consumer is not validating against stale tarballs or source aliases.
|
|
3260
3296
|
253. **`overridePrimitive('icon')` returns a RenderNode, not JSX** (v0.1.0). Use it only for full primitive replacement. The renderer function must return `{ type, props, children }` with `_component` in props when targeting React. Returning `<Icon />` directly is not the primitive renderer contract and bypasses the built-in icon identity wrapper.
|
|
3261
3297
|
254. **CLI explicit input wins over ambient stdin** (v0.1.0). For `mythik push`/`mythik patch`, `--from-file <path>` reads the file even if the host process exposes non-TTY stdin. Intentional stdin remains supported through `--from-file -` or by piping without an explicit file. `--from-file` plus a positional patch argument is still a conflict.
|
|
3262
3298
|
255. **`runPatch` versions in every output mode when `author` is provided** (v0.1.0). `SpecEngine.patch` applies and validates patches. CLI/API `runPatch` persists through the normal `store.save` path without `author`; with a versioned store + `author`, it captures the patched document and writes once through `saveVersion`, preserving lazy-bootstrap pre-patch history. JSON/TOON success output includes additive `versioned` and `version` metadata.
|
|
@@ -3309,19 +3345,21 @@ See `ai-context.md` for spec-gen anti-patterns the AI must NOT generate.
|
|
|
3309
3345
|
|
|
3310
3346
|
281. **`MythikApp.fetcher` supplies editor persistence when auth fetch is absent** - React hosts can pass `fetcher={(url, options) => ...}` to `MythikApp` so `editorSave` and `navigationGuardSaveAndProceed` have a transport in non-auth apps. When auth is configured, the framework fetch with auth interceptors remains the active fetcher. Save actions do not read global `/ui/lastError`; editor save status, errors, and attempts are reported under `/ui/editorSessions/<id>`.
|
|
3311
3347
|
|
|
3312
|
-
282. **Existing spec edits must use the CLI inspection-then-patch loop** - For an existing screen/app/api spec, AI agents should run `mythik manifest <id>` first, inspect only the target nodes with `mythik elements <id> <ids>`, apply a small RFC 6902 patch with `mythik patch <id> --from-file patch.json --author <agent>`, validate, and verify with `manifest` or `elements`. This keeps edits surgical, validated, versionable, and reviewable. `pull` is for backup, migration, review, or full-document work; `push` is for new specs or intentional full replacement with explicit `--replace`. Direct database edits and direct `SpecStore.save()` calls bypass validation and are not approved spec-write paths.
|
|
3348
|
+
282. **Existing spec edits must use the CLI inspection-then-patch loop** - For an existing screen/app/api spec, AI agents should run `mythik manifest <id>` first, inspect only the target nodes with `mythik elements <id> <ids>`, apply a small RFC 6902 patch with `mythik patch <id> --from-file patch.json --author <agent>`, validate, and verify with `manifest` or `elements`. This keeps edits surgical, validated, versionable, and reviewable. `pull` is for backup, migration, review, or full-document work; `push` is for new specs or intentional full replacement with explicit `--replace`. Direct database edits and direct `SpecStore.save()` calls bypass validation and are not approved spec-write paths.
|
|
3313
3349
|
283. **Bundled AI docs are part of the install surface** - The `mythik` package includes `docs/llms.txt`, `docs/consumer/*`, and `docs/wiki/compiled/*`. Agents should run `mythik docs path` before spec generation and read the bundled docs rather than guessing from package source. Use `mythik docs copy ./mythik-docs` to create a project-local copy when the host workflow needs explicit files.
|
|
3314
3350
|
284. **DNA numeric seeds are canonical `0–1`, with legacy `0–100` normalization** - Generate `tokens.dna.roundness`, `density`, `depth`, and `formality` as `0–1` numbers (`0.7`, not `70`). The runtime normalizes numeric seed values greater than `1` by dividing by `100` inside DNA derivation, so initial AppSpec load and runtime `updateTokens` share the same backward-compatible behavior.
|
|
3315
3351
|
285. **Scoped pagination counts filter before aggregation** - Query endpoints may combine `pagination: "offset"` with `scopeFilter`. For generated counts, the server applies the scope filter to the query source first and then counts the scoped source, so the response `total` matches the same tenant/role slice as `data`. Prefer generated counts. If custom `endpoint.count` is truly needed with `scopeFilter`, it must 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. Specs should use `:alias` for JOIN/subquery counts and should not reference internal scope parameter names directly.
|
|
3316
3352
|
286. **Transaction fetch failures preserve backend error details** - When a transaction `confirm` uses `fetch` and the backend returns an HTTP error payload such as `{ error: { code, message } }`, `/tx/error` is written after rollback with the best backend message plus `code`, HTTP `status`, and raw `data`. `onError` should read `/tx/error/message`; transaction specs should not read global `/ui/lastError`.
|
|
3317
|
-
287. **SQL-backed stores and servers use one dialect-aware `mythik/server` boundary** - Import `createSqlDriver`, `SqlSpecStore`, `SqlVersionedSpecStore`, `SqlEnvironmentStore`, and `getSqlStoreDdl` from `mythik/server` for Node-side SQL work. Supported dialects are `sqlserver`, `postgres`, `mysql`, and `sqlite`. Initialize store tables with `mythik init-store --dialect <dialect>` for reachable SQL stores, `--target` for SQLite, or `--dry-run` for review/apply through a deployment process. SQL Server `init-store` accepts explicit `--server`, `--database`, `--user`, `--password`, `--encrypt`, and `--trust-server-certificate` flags. CLI commands share the same store flags/env vars and must keep existing-spec edits on the `manifest -> elements -> patch --from-file --author -> validate -> verify` loop. ApiSpec `dialect` controls generated CRUD/catalog/pagination/scope SQL; custom SQL remains dialect-native with Mythik named params (`@name`) and is not translated between dialects.
|
|
3353
|
+
287. **SQL-backed stores and servers use one dialect-aware `mythik/server` boundary** - Import `createSqlDriver`, `SqlSpecStore`, `SqlVersionedSpecStore`, `SqlEnvironmentStore`, and `getSqlStoreDdl` from `mythik/server` for Node-side SQL work. Supported dialects are `sqlserver`, `postgres`, `mysql`, and `sqlite`. Initialize store tables with `mythik init-store --dialect <dialect>` for reachable SQL stores, `--target` for SQLite, or `--dry-run` for review/apply through a deployment process. SQL Server `init-store` accepts explicit `--server`, `--database`, `--user`, `--password`, `--encrypt`, and `--trust-server-certificate` flags. CLI commands share the same store flags/env vars and must keep existing-spec edits on the `manifest -> elements -> patch --from-file --author -> validate -> verify` loop. ApiSpec `dialect` controls generated CRUD/catalog/pagination/scope SQL; custom SQL remains dialect-native with Mythik named params (`@name`) and is not translated between dialects.
|
|
3318
3354
|
288. **Event arrays may mix actions and transactions** - Event bindings can be a single action, a single transaction, or an array containing both normal action bindings and transaction bindings. Mythik executes the array sequentially and awaits each transaction before continuing. Transaction phases cannot contain nested transactions.
|
|
3319
3355
|
289. **`$let` dotted references read nested binding values** - A `$ref` may target an object binding path such as `{ "$ref": "user.name" }`, and `$template` placeholders may read the same path as `${user.name}`. Use this for object values produced by `$let`; missing dotted `$ref` segments are invalid references and should be fixed instead of treated as optional data.
|
|
3320
3356
|
290. **`params.skipIf` is a dispatch-time action guard** - Any action binding may include `params.skipIf`. Mythik resolves it before resolving the rest of the params; when truthy, the action is skipped and the action chain continues. The action handler never receives `skipIf`.
|
|
3321
3357
|
291. **Direct `fetch` supports `errorTarget` for visible screen-load failures** - `fetch.params.errorTarget` writes HTTP/network errors to a consumer-owned state path and clears it on success. Use it for critical `initialActions` loads so the screen can render a local banner/empty state; `/ui/lastError` remains global compatibility state and can be overwritten by unrelated fetches.
|
|
3322
|
-
292. **`select` supports catalog keys and invalid-option diagnostics** - `select.options` may be strings, `{ label, value }`, or catalog-shaped objects when `labelKey`/`valueKey` are provided. Values emitted from the primitive
|
|
3358
|
+
292. **`select` supports catalog keys, normalized matching, and invalid-option diagnostics** - `select.options` may be strings, `{ label, value }`, or catalog-shaped objects when `labelKey`/`valueKey` are provided. The current value is matched against options by normalized scalar key, so DB integer IDs and string option values match for display. `0` is a valid selected value. Null/undefined show the placeholder. Values emitted from the primitive remain string-compatible. Malformed option data renders as disabled diagnostics instead of blank clickable options or crashes, so AI-generated catalog bindings fail visibly.
|
|
3323
3359
|
293. **SQL adapters are optional peer dependencies** - `mythik` does not install SQL drivers by default. Browser-only apps install `mythik mythik-react`. SQL-backed stores/servers must install exactly the selected adapter (`mssql`, `pg`, `mysql2`, or `better-sqlite3`). SQLite uses native `better-sqlite3`; warnings from its transitive native-build helpers are adapter-level install warnings, not Mythik runtime failures.
|
|
3324
3360
|
294. **Missing SQL adapter errors are actionable** - If a SQL-backed store or server uses a dialect whose adapter package is not installed, Mythik throws `SqlDriverError` with `code: "SQL_DRIVER_DEPENDENCY_MISSING"`, `packageName`, `installCommand`, and a message containing the exact `npm install ...` command.
|
|
3325
3361
|
295. **`mythik-react-native` publishes an explicit native support contract** - Expo apps should install React Native/Expo peer packages with `npx expo install ...`, including `react-native-reanimated` and its Expo-matched `react-native-worklets` peer, 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. The package exports `REACT_NATIVE_PRIMITIVE_SUPPORT` and `getReactNativePrimitiveSupport(name)`. Supported native primitives are `box`, `stack`, `grid`, `scroll`, `divider`, `spacer`, `text`, `image`, `icon`, `input`, `textarea`, `select`, `checkbox`, `toggle`, `slider`, `button`, `touchable`, `list`, `modal`, `drawer`, `tabs`, `accordion`, `wizard`, `screen`, `screen-outlet`, `toast-container`, and `skeleton`. Native-milestone primitives are `bar-chart`, `line-chart`, `pie-chart`, `area-chart`, `table`, `kanban-board`, `spatial-map`, `file-upload`, `camera`, `signature`, and `audio-player`; they should surface diagnostics instead of silently rendering broken UI. Keep `root` as a stable string and use `$platform` only in localized props/style/children/value branches.
|
|
3326
3362
|
296. **Mythik Reveal is the live-context bridge for AI agents** - Before guessing about running-app behavior, start `mythik reveal start`, wire the host `reveal` config in development, and inspect with `mythik reveal apps`, `context`, `current`, `screen`, or `element`. Reveal exposes renderer/environment/spec summaries, selected state paths, resolved public props, dependencies, render errors, warnings, events, patch-target metadata, and redaction/truncation metadata as structured JSON. It complements `manifest -> elements -> patch`: use the CLI loop to edit stored specs, and use Reveal to understand the app that is actually running. Keep it development-only, never commit tokens, memoize React/RN reveal config objects, use narrow `includeStatePaths`, and redact secrets deliberately.
|
|
3327
|
-
297. **`mythik agent context
|
|
3363
|
+
297. **`mythik agent context`, `mythik agent init`, and Mythik Sentinel install and reinforce the AI operating contract**. Use `mythik agent init codex`, `mythik agent init claude`, or `mythik agent init all` to create `.mythik/agent/*` plus thin agent adapters. `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. Use `mythik agent context --app <id> --include-screens` to generate the project-specific operating map. The generated protocol requires existing stored specs to use `manifest -> elements -> patch --from-file --author -> validate -> verify`, names the active store as the source of truth, recommends TOON for token-efficient reads when supported, and scopes `lint` to local drafts, replacement files, bulk import/migration folders, and relevant consumer code. Sentinel runs as advisory CLI coaching: first project use points agents to `agent init`, repeated full-replacement intent warns back to patch-first edits, identical `push --replace` writes are skipped as `skipped: true`, machine-readable outputs stay parseable, and no specs or credentials are persisted in the Sentinel cache. Disable only with `MYTHIK_SENTINEL=off` for exceptional automation.
|
|
3364
|
+
298. **`repeat.layout` controls repeated item rows**. `repeat.layout` accepts `{ direction, gap, wrap }` and lets repeated items render horizontally or wrap without changing the child primitive. In grouped repeats, group headers and footers keep the outer vertical flow; the layout applies only to the group item row.
|
|
3365
|
+
299. **`text.on.press` is supported for inline interactive text**. Web text receives button semantics, `tabIndex=0`, pointer cursor, and Enter/Space keyboard activation. React Native text uses a pressable wrapper with `accessibilityRole="button"`. Use `button` or `touchable` for primary actions and larger tap targets.
|
|
@@ -7,9 +7,17 @@ sources: [docs/consumer/ai-context.md#component-variants, docs/consumer/referenc
|
|
|
7
7
|
|
|
8
8
|
# Component variants
|
|
9
9
|
|
|
10
|
-
Token-driven component styling. Define variant definitions in
|
|
11
|
-
`tokens.components.{primitiveType}.{variantName}`. The engine applies
|
|
12
|
-
style, hover, active, focus, transition, animations automatically.
|
|
10
|
+
Token-driven component styling. Define variant definitions in
|
|
11
|
+
`tokens.components.{primitiveType}.{variantName}`. The engine applies
|
|
12
|
+
style, hover, active, focus, transition, animations automatically.
|
|
13
|
+
|
|
14
|
+
Use variants before copying the same visual style block into multiple
|
|
15
|
+
elements. Variants are intentionally limited to primitive visual slots:
|
|
16
|
+
`style`, `hover`, `active`, `focus`, `transition`, and `animations`.
|
|
17
|
+
They do not carry arbitrary primitive props such as table `headerStyle`,
|
|
18
|
+
table `rowStyle`, `columns`, `onRowClick`, action bindings, or child
|
|
19
|
+
composition. Use [[@concept-templates-vs-variants]] when the repeated
|
|
20
|
+
pattern needs those props.
|
|
13
21
|
|
|
14
22
|
## Defining
|
|
15
23
|
|
|
@@ -49,9 +57,28 @@ style, hover, active, focus, transition, animations automatically.
|
|
|
49
57
|
`variant` is **universal** — any primitive can use it when defined in
|
|
50
58
|
`tokens.components`.
|
|
51
59
|
|
|
52
|
-
## Supported variant fields
|
|
53
|
-
|
|
54
|
-
`style`, `hover`, `active`, `focus`, `transition`, `animations`.
|
|
60
|
+
## Supported variant fields
|
|
61
|
+
|
|
62
|
+
`style`, `hover`, `active`, `focus`, `transition`, `animations`.
|
|
63
|
+
|
|
64
|
+
## Not supported inside primitive variants
|
|
65
|
+
|
|
66
|
+
Do not put these in `tokens.components.{type}.{variant}` and expect the
|
|
67
|
+
primitive to receive them:
|
|
68
|
+
|
|
69
|
+
- `headerStyle` / `rowStyle` on `table`
|
|
70
|
+
- `columns`, `pagination`, `selection`, `groupBy`, `onRowClick`
|
|
71
|
+
- action bindings
|
|
72
|
+
- composed children
|
|
73
|
+
|
|
74
|
+
For reusable table chrome, put the surrounding card style in a `box`
|
|
75
|
+
variant and wrap the `table` in an AppSpec template that passes
|
|
76
|
+
`headerStyle`, `rowStyle`, `columns`, and actions through `$prop`.
|
|
77
|
+
|
|
78
|
+
For filter chips composed from `touchable` + `text`, keep static shell
|
|
79
|
+
and label styling in variants, then keep active `$state` / `$item`
|
|
80
|
+
expressions on the actual elements. Variants do not evaluate render
|
|
81
|
+
context expressions such as `$state`, `$item`, or `$prop` by themselves.
|
|
55
82
|
|
|
56
83
|
## `$path` references
|
|
57
84
|
|
|
@@ -70,10 +97,12 @@ Variant is base, element-level overrides — same as CSS class + inline
|
|
|
70
97
|
override. Hover merges per-key (variant's `scale: 1.05` + element's
|
|
71
98
|
`rotate: 5` both apply).
|
|
72
99
|
|
|
73
|
-
## Constraints / Anti-patterns
|
|
74
|
-
|
|
75
|
-
- **Place `variant` in `props`**, not as a top-level field. Top-level is
|
|
76
|
-
silently ignored. See [[@antipattern-element-variant-top-level]].
|
|
100
|
+
## Constraints / Anti-patterns
|
|
101
|
+
|
|
102
|
+
- **Place `variant` in `props`**, not as a top-level field. Top-level is
|
|
103
|
+
silently ignored. See [[@antipattern-element-variant-top-level]].
|
|
104
|
+
- **Do not copy table chrome into every table.** Use a template for the
|
|
105
|
+
prop-bearing table defaults and a variant for the panel/card shell.
|
|
77
106
|
|
|
78
107
|
## Related concepts
|
|
79
108
|
|
|
@@ -11,19 +11,36 @@ Two underused reuse mechanisms. **Use them before duplicating style blocks.**
|
|
|
11
11
|
|
|
12
12
|
## Decision table
|
|
13
13
|
|
|
14
|
-
| Situation | Pick |
|
|
15
|
-
|---|---|
|
|
16
|
-
| Same primitive type, different style set | `tokens.components.{type}.{variant}` |
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
14
|
+
| Situation | Pick |
|
|
15
|
+
|---|---|
|
|
16
|
+
| Same primitive type, different style set | `tokens.components.{type}.{variant}` |
|
|
17
|
+
| Primitive style plus repeated primitive props such as table `headerStyle` / `rowStyle` | `appSpec.templates` |
|
|
18
|
+
| Composite (custom type wrapping primitive + children slot) | `appSpec.templates` |
|
|
19
|
+
| Style varies by state (hover/active/focus) | Variants (built-in state slots) |
|
|
20
|
+
| Parametrized via props + children | Templates (with `$prop` + `$children`) |
|
|
20
21
|
|
|
21
22
|
## Trade-off
|
|
22
23
|
|
|
23
|
-
- **Variants are lightweight** and integrate natively with primitive
|
|
24
|
-
rendering. Prefer when you only vary style
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
- **Variants are lightweight** and integrate natively with primitive
|
|
25
|
+
rendering. Prefer when you only vary style, hover, active, focus,
|
|
26
|
+
transition, or animations.
|
|
27
|
+
- **Templates are more flexible** but more verbose. Use when you compose
|
|
28
|
+
structure or need reusable primitive props beyond visual slots.
|
|
29
|
+
|
|
30
|
+
## Important boundary
|
|
31
|
+
|
|
32
|
+
`tokens.components` variants do not carry arbitrary primitive props.
|
|
33
|
+
For example, a `table` variant is not the right place for `headerStyle`,
|
|
34
|
+
`rowStyle`, `columns`, `pagination`, `selection`, `groupBy`, or
|
|
35
|
+
`onRowClick`. Those are primitive props, not variant visual slots.
|
|
36
|
+
|
|
37
|
+
Use a template when the repeated pattern needs those props:
|
|
38
|
+
|
|
39
|
+
- `box.tableCard` variant for the shared panel shell.
|
|
40
|
+
- `ops-table` template for the actual table with shared `headerStyle`
|
|
41
|
+
and `rowStyle`.
|
|
42
|
+
- `$prop` pass-through for screen-specific `data`, `columns`, actions,
|
|
43
|
+
pagination, selection, grouping, and empty states.
|
|
27
44
|
|
|
28
45
|
## Example — variant (style-only)
|
|
29
46
|
|
|
@@ -60,9 +77,56 @@ Use: `{ "type": "button", "props": { "variant": "ctaPulse", "label": "..." } }`.
|
|
|
60
77
|
}
|
|
61
78
|
```
|
|
62
79
|
|
|
63
|
-
Use: `{ "type": "button-pulse-cta", "props": { "label": "Sign Up", "padding": "10px 20px" } }`.
|
|
64
|
-
|
|
65
|
-
##
|
|
80
|
+
Use: `{ "type": "button-pulse-cta", "props": { "label": "Sign Up", "padding": "10px 20px" } }`.
|
|
81
|
+
|
|
82
|
+
## Example -> table chrome template
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"tokens": {
|
|
87
|
+
"components": {
|
|
88
|
+
"box": {
|
|
89
|
+
"tableCard": {
|
|
90
|
+
"style": {
|
|
91
|
+
"backgroundColor": "#FFFFFF",
|
|
92
|
+
"border": "1px solid #E2E8F0",
|
|
93
|
+
"borderRadius": 16,
|
|
94
|
+
"padding": 12
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"templates": {
|
|
101
|
+
"ops-table": {
|
|
102
|
+
"type": "table",
|
|
103
|
+
"props": {
|
|
104
|
+
"data": { "$prop": "data" },
|
|
105
|
+
"columns": { "$prop": "columns" },
|
|
106
|
+
"headerStyle": { "minHeight": 44, "background": "#F8FAFC" },
|
|
107
|
+
"rowStyle": {
|
|
108
|
+
"base": { "minHeight": 43 },
|
|
109
|
+
"hover": { "backgroundColor": "#F8FAFC" }
|
|
110
|
+
},
|
|
111
|
+
"pagination": { "$prop": "pagination" },
|
|
112
|
+
"onRowClick": { "$prop": "onRowClick" }
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Use the card variant around the template:
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"type": "box",
|
|
124
|
+
"props": { "variant": "tableCard" },
|
|
125
|
+
"children": ["orders-table"]
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Animations cascade across both
|
|
66
130
|
|
|
67
131
|
`animations` declared at any of these levels merges via the cascade —
|
|
68
132
|
identity → variant → elementDef → template → element. See
|