openuispec 0.2.8 → 0.2.9
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 +50 -385
- package/cli/init.ts +9 -4
- package/docs/cli.md +130 -0
- package/docs/file-formats.md +84 -0
- package/mcp-server/screenshot-android.ts +14 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
> A single source of truth design language for AI-native, platform-native app development.
|
|
4
4
|
|
|
5
|
-
OpenUISpec is a **semantic UI specification format** that replaces cross-platform frameworks with a declarative design language.
|
|
6
|
-
|
|
7
|
-
OpenUISpec is a shared UI sync language for native products, optimized for solo developers but equally usable by teams. It is not a pixel-perfect design format like Figma and it is not a shared runtime like Flutter or React Native. Its job is to keep product intent, interaction contracts, flows, tokens, and platform outputs aligned while still allowing bounded native variation on iOS, Android, and web.
|
|
5
|
+
OpenUISpec is a **semantic UI specification format** that replaces cross-platform frameworks with a declarative design language.
|
|
6
|
+
Instead of sharing runtime code across platforms, you share the *spec* — and AI generates native SwiftUI, Jetpack Compose, and React code from it.
|
|
8
7
|
|
|
9
8
|
## Why
|
|
10
9
|
|
|
11
|
-
Cross-platform frameworks (Flutter, React Native, KMP/CMP) solve code duplication by sharing a runtime.
|
|
10
|
+
Cross-platform frameworks (Flutter, React Native, KMP/CMP) solve code duplication by sharing a runtime.
|
|
11
|
+
OpenUISpec solves it by sharing **intent**:
|
|
12
12
|
|
|
13
13
|
| Approach | Shares | Runs |
|
|
14
14
|
|----------|--------|------|
|
|
@@ -33,17 +33,6 @@ The result: each platform feels native, but every app stays semantically consist
|
|
|
33
33
|
<img alt="OpenUISpec workflows" src="https://raw.githubusercontent.com/rsktash/openuispec/main/docs/images/workflows-light.png">
|
|
34
34
|
</picture>
|
|
35
35
|
|
|
36
|
-
## Key concepts
|
|
37
|
-
|
|
38
|
-
- **Tokens**: Design values (color, typography, spacing, elevation, motion) with semantic names and constrained ranges
|
|
39
|
-
- **Contracts**: 7 behavioral component families defined by role, props, state machines, and accessibility
|
|
40
|
-
- **Screens**: Compositions of contracts with data bindings, adaptive layout, and conditional rendering
|
|
41
|
-
- **Flows**: Multi-screen navigation journeys, intent-based and platform-agnostic
|
|
42
|
-
- **Actions**: 13 typed action types with composition, error handling, and optimistic updates
|
|
43
|
-
- **Data binding**: Reactive state, format expressions, caching, and loading/error/empty states
|
|
44
|
-
- **Adaptive layout**: Size classes (compact/regular/expanded) with per-section overrides
|
|
45
|
-
- **Platform adaptation**: Per-target overrides for iOS, Android, and Web behaviors
|
|
46
|
-
|
|
47
36
|
## Quick start
|
|
48
37
|
|
|
49
38
|
```bash
|
|
@@ -52,399 +41,75 @@ cd your-project
|
|
|
52
41
|
openuispec init
|
|
53
42
|
```
|
|
54
43
|
|
|
55
|
-
This scaffolds a spec directory, starter tokens, and **configures the MCP server** for your AI coding agent (Claude Code, VS Code/Copilot, Codex
|
|
56
|
-
|
|
57
|
-
## AI integration (MCP)
|
|
58
|
-
|
|
59
|
-
OpenUISpec is designed to be used by AI coding agents. The package includes an **MCP server** that exposes tools AI assistants call automatically during UI work — no manual prompting needed.
|
|
60
|
-
|
|
61
|
-
### How it works
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
-
openuispec init → configures MCP for your agent → AI calls tools automatically
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
When you ask your AI to "add a settings page" or "update the home feed," the MCP server:
|
|
68
|
-
|
|
69
|
-
1. **Schema reference** — `openuispec_spec_types` and `openuispec_spec_schema` give the AI the exact format for any spec file it needs to create or edit
|
|
70
|
-
2. **Before generation** — `openuispec_prepare` gives the AI your spec context, platform config, and constraints
|
|
71
|
-
3. **During generation** — `openuispec_read_specs` feeds the AI the actual spec file contents as the authoritative source
|
|
72
|
-
4. **After generation** — `openuispec_check` returns a concrete audit checklist derived from your spec (every contract `must_handle` item, every screen section, every locale key) and the AI verifies its code matches
|
|
73
|
-
|
|
74
|
-
This replaces the old approach of writing instructions in CLAUDE.md and hoping the AI follows them. MCP tools are called reliably because they're part of the AI's tool-calling loop, not a text instruction it can skip.
|
|
75
|
-
|
|
76
|
-
### Setup
|
|
77
|
-
|
|
78
|
-
`openuispec init` and `openuispec update-rules` automatically configure MCP for all supported agents:
|
|
79
|
-
|
|
80
|
-
| Agent | Config file | Created automatically |
|
|
81
|
-
|-------|------------|----------------------|
|
|
82
|
-
| **Claude Code** | `.mcp.json` | Always |
|
|
83
|
-
| **Codex** | `.codex/config.toml` | Always |
|
|
84
|
-
| **VS Code / Copilot** | `.vscode/mcp.json` | If `.vscode/` exists |
|
|
85
|
-
| **Gemini CLI** | `.gemini/settings.json` | If `.gemini/` exists |
|
|
86
|
-
|
|
87
|
-
Manual setup (if needed):
|
|
88
|
-
|
|
89
|
-
**Claude Code** (`.mcp.json`), **VS Code / Copilot** (`.vscode/mcp.json`), **Gemini CLI** (`.gemini/settings.json`):
|
|
90
|
-
```json
|
|
91
|
-
{
|
|
92
|
-
"mcpServers": {
|
|
93
|
-
"openuispec": {
|
|
94
|
-
"command": "openuispec",
|
|
95
|
-
"args": ["mcp"]
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
**Codex** (`.codex/config.toml`):
|
|
102
|
-
```toml
|
|
103
|
-
[mcp_servers.openuispec]
|
|
104
|
-
command = "openuispec"
|
|
105
|
-
args = ["mcp"]
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
Or run directly: `openuispec mcp`
|
|
109
|
-
|
|
110
|
-
### Tools
|
|
111
|
-
|
|
112
|
-
| Tool | When | What it does |
|
|
113
|
-
|------|------|-------------|
|
|
114
|
-
| `openuispec_spec_types` | Before creating spec files | Lists all available spec types with descriptions — discover what kinds of spec files exist |
|
|
115
|
-
| `openuispec_spec_schema` | Before creating/editing spec files | Returns the full JSON schema for a specific spec type — exact structure, required fields, allowed values |
|
|
116
|
-
| `openuispec_prepare` | Before UI code generation | Returns spec context, platform config, generation constraints |
|
|
117
|
-
| `openuispec_read_specs` | Before and after generation | Loads spec file contents — the authoritative source for tokens, screens, contracts |
|
|
118
|
-
| `openuispec_check` | After generation | Schema validation + concrete audit checklist from your spec. Optional `screens`/`contracts` params scope the audit |
|
|
119
|
-
| `openuispec_validate` | After spec edits | Schema-only validation, optionally filtered by group |
|
|
120
|
-
| `openuispec_drift` | Before updates | Detect spec drift since last snapshot, with semantic explanation |
|
|
121
|
-
| `openuispec_status` | Anytime | Cross-target summary: baselines, drift, next steps |
|
|
122
|
-
| `openuispec_get_screen` | Incremental edits | Get a single screen spec by name — faster than `read_specs` for targeted work |
|
|
123
|
-
| `openuispec_get_contract` | Incremental edits | Get a single contract spec, optionally filtered to one variant |
|
|
124
|
-
| `openuispec_get_tokens` | Incremental edits | Get tokens for a specific category (color, typography, spacing, etc.) |
|
|
125
|
-
| `openuispec_get_locale` | Incremental edits | Get a single locale file, optionally filtered to specific keys |
|
|
126
|
-
| `openuispec_screenshot` | Visual verification | Screenshot the web app at a route via headless browser (requires `puppeteer`) |
|
|
127
|
-
| `openuispec_screenshot_android` | Visual verification | Screenshot Android app on emulator — builds APK, installs, captures via adb. Works with any Android project via `project_dir` param |
|
|
128
|
-
| `openuispec_screenshot_ios` | Visual verification | Screenshot iOS app on Simulator — builds with xcodebuild, captures via XCUITest. Works with any iOS project via `project_dir` param |
|
|
129
|
-
|
|
130
|
-
The server includes **protocol-level instructions** that trigger on UI-related requests independently of CLAUDE.md rules — so even if CLAUDE.md is buried under other project rules, the MCP enforcement still works.
|
|
131
|
-
|
|
132
|
-
### Visual verification
|
|
133
|
-
|
|
134
|
-
The screenshot tools work with **any** Android/iOS/web project — they don't require an OpenUISpec manifest. Use `project_dir` to point directly at a project root:
|
|
135
|
-
|
|
136
|
-
```
|
|
137
|
-
# With OpenUISpec manifest (auto-discovers generated app)
|
|
138
|
-
openuispec_screenshot_android(screen: "home")
|
|
139
|
-
|
|
140
|
-
# Standalone — any Android project
|
|
141
|
-
openuispec_screenshot_android(project_dir: "/path/to/android/project", screen: "home")
|
|
142
|
-
|
|
143
|
-
# Standalone — any iOS project
|
|
144
|
-
openuispec_screenshot_ios(project_dir: "/path/to/ios/project", scheme: "MyApp")
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
Additional override params:
|
|
44
|
+
This scaffolds a spec directory, starter tokens, and **configures the MCP server** for your AI coding agent (Claude Code, VS Code/Copilot, Codex, Gemini CLI).
|
|
148
45
|
|
|
149
|
-
|
|
150
|
-
|-------|---------|-----|---------|
|
|
151
|
-
| `project_dir` | yes | yes | Skip manifest, point directly at project root |
|
|
152
|
-
| `module` | yes | — | Override app module name (default: auto-detect from `settings.gradle`) |
|
|
153
|
-
| `scheme` | — | yes | Override Xcode scheme (default: auto-detect) |
|
|
154
|
-
| `bundle_id` | — | yes | Override bundle ID (default: auto-detect from `project.pbxproj`) |
|
|
155
|
-
|
|
156
|
-
Auto-detection features:
|
|
157
|
-
- **Android**: Scans `settings.gradle.kts`/`.gradle` to find the module with `com.android.application` plugin. Supports both Kotlin DSL and Groovy DSL.
|
|
158
|
-
- **iOS**: Reads deployment target from `project.pbxproj`. For navigation screenshots, generates an XCUITest project via xcodegen — works with both xcodegen-managed and standalone Xcode projects.
|
|
159
|
-
|
|
160
|
-
## Using without MCP
|
|
161
|
-
|
|
162
|
-
You can also use OpenUISpec with any AI by providing context manually:
|
|
163
|
-
|
|
164
|
-
> Generate a native iOS app from this OpenUISpec. Follow all contract state machines, apply token ranges for iOS, and implement navigation flows as defined. Use `platform/ios.yaml` for SwiftUI-specific overrides.
|
|
165
|
-
|
|
166
|
-
For platform generation, treat these as hard output constraints:
|
|
46
|
+
## Key concepts
|
|
167
47
|
|
|
168
|
-
-
|
|
169
|
-
-
|
|
170
|
-
-
|
|
48
|
+
- **Tokens** — design values (color, typography, spacing, elevation, motion) with semantic names and constrained ranges
|
|
49
|
+
- **Contracts** — 7 behavioral component families defined by role, props, state machines, and accessibility
|
|
50
|
+
- **Screens** — compositions of contracts with data bindings, adaptive layout, and conditional rendering
|
|
51
|
+
- **Flows** — multi-screen navigation journeys, intent-based and platform-agnostic
|
|
52
|
+
- **Actions** — 13 typed action types with composition, error handling, and optimistic updates
|
|
53
|
+
- **Data binding** — reactive state, format expressions, caching, and loading/error/empty states
|
|
54
|
+
- **Adaptive layout** — size classes (compact/regular/expanded) with per-section overrides
|
|
55
|
+
- **Platform adaptation** — per-target overrides for iOS, Android, and Web behaviors
|
|
171
56
|
|
|
172
|
-
|
|
57
|
+
## The 7 contract families
|
|
173
58
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
59
|
+
| Contract | Role | Maps to |
|
|
60
|
+
|----------|------|---------|
|
|
61
|
+
| `action_trigger` | Initiates actions | Button, FAB, link |
|
|
62
|
+
| `data_display` | Shows read-only info | Card, list item, stat |
|
|
63
|
+
| `input_field` | Captures user input | TextField, toggle, picker |
|
|
64
|
+
| `nav_container` | Persistent navigation | Tab bar, sidebar, drawer |
|
|
65
|
+
| `feedback` | System status messages | Toast, dialog, banner |
|
|
66
|
+
| `surface` | Contains other components | Sheet, modal, popover |
|
|
67
|
+
| `collection` | Repeating data sets | List, grid, table |
|
|
177
68
|
|
|
178
|
-
##
|
|
69
|
+
## AI integration (MCP)
|
|
179
70
|
|
|
180
|
-
|
|
181
|
-
openuispec/
|
|
182
|
-
├── spec/
|
|
183
|
-
│ └── openuispec-v0.1.md # Full specification (14 sections)
|
|
184
|
-
├── schema/ # JSON Schema for validation (draft 2020-12)
|
|
185
|
-
│ ├── openuispec.schema.json # Root manifest schema
|
|
186
|
-
│ ├── screen.schema.json # Screen composition schema
|
|
187
|
-
│ ├── flow.schema.json # Navigation flow schema
|
|
188
|
-
│ ├── platform.schema.json # Platform adaptation schema
|
|
189
|
-
│ ├── locale.schema.json # Locale file schema
|
|
190
|
-
│ ├── contract.schema.json # Standard contract extension schema
|
|
191
|
-
│ ├── custom-contract.schema.json # Custom contract extension schema (x_ prefixed)
|
|
192
|
-
│ ├── tokens/
|
|
193
|
-
│ │ ├── color.schema.json # Color token schema
|
|
194
|
-
│ │ ├── typography.schema.json # Typography token schema
|
|
195
|
-
│ │ ├── spacing.schema.json # Spacing token schema
|
|
196
|
-
│ │ ├── elevation.schema.json # Elevation token schema
|
|
197
|
-
│ │ ├── motion.schema.json # Motion token schema
|
|
198
|
-
│ │ ├── layout.schema.json # Layout token schema
|
|
199
|
-
│ │ ├── themes.schema.json # Theme token schema
|
|
200
|
-
│ │ └── icons.schema.json # Icon token schema
|
|
201
|
-
│ ├── defs/
|
|
202
|
-
│ │ ├── common.schema.json # Shared types (icons, badges, etc.)
|
|
203
|
-
│ │ ├── action.schema.json # 14 action types (discriminated union)
|
|
204
|
-
│ │ ├── data-binding.schema.json # Data sources, state, params
|
|
205
|
-
│ │ ├── adaptive.schema.json # Adaptive override pattern
|
|
206
|
-
│ │ └── validation.schema.json # Validation rule definitions
|
|
207
|
-
│ └── validate.ts # Validation script (npm run validate)
|
|
208
|
-
├── examples/
|
|
209
|
-
│ ├── taskflow/ # Compact reference sample
|
|
210
|
-
│ │ ├── openuispec/ # Source OpenUISpec project
|
|
211
|
-
│ │ ├── generated/ # Generated iOS, Android, and web apps
|
|
212
|
-
│ │ ├── README.md # Sample overview and structure
|
|
213
|
-
│ │ └── AGENTS.md / CLAUDE.md # AI rules generated from the package
|
|
214
|
-
│ ├── social-app/ # Social app sample (trilingual, Android + Web)
|
|
215
|
-
│ └── todo-orbit/ # Full showcase sample
|
|
216
|
-
│ ├── openuispec/ # Source OpenUISpec project
|
|
217
|
-
│ ├── generated/ # Generated iOS, Android, and web apps
|
|
218
|
-
│ ├── README.md # Sample overview and structure
|
|
219
|
-
│ └── AGENTS.md / CLAUDE.md # AI rules generated from the package
|
|
220
|
-
├── cli/ # CLI tool (openuispec init, drift, prepare, validate)
|
|
221
|
-
│ ├── index.ts # Entry point
|
|
222
|
-
│ └── init.ts # Project scaffolding + AI rules
|
|
223
|
-
├── mcp-server/ # MCP server (openuispec-mcp)
|
|
224
|
-
│ ├── index.ts # Stdio transport, 15 tools
|
|
225
|
-
│ ├── screenshot.ts # Dev server + headless browser screenshot (web)
|
|
226
|
-
│ ├── screenshot-shared.ts # Shared utilities for platform screenshot tools
|
|
227
|
-
│ ├── screenshot-android.ts # Android screenshot via emulator (adb screencap)
|
|
228
|
-
│ └── screenshot-ios.ts # iOS screenshot via Simulator (xcodebuild + XCUITest)
|
|
229
|
-
├── scripts/
|
|
230
|
-
│ └── take-all-screenshots.ts # Batch screenshot capture for all example projects
|
|
231
|
-
├── artifacts/ # Screenshot artifacts from generated apps
|
|
232
|
-
│ ├── social-app/screenshots/ # Web + Android screenshots
|
|
233
|
-
│ ├── todo-orbit/screenshots/ # Web + Android + iOS screenshots
|
|
234
|
-
│ └── taskflow/screenshots/ # Web + Android + iOS screenshots
|
|
235
|
-
├── check/ # Composite validation command
|
|
236
|
-
│ └── index.ts # Schema + semantic + readiness
|
|
237
|
-
├── drift/ # Drift detection (spec change tracking)
|
|
238
|
-
│ └── index.ts # Hash-based drift checker
|
|
239
|
-
├── prepare/ # Target work bundle generation
|
|
240
|
-
│ └── index.ts # Baseline-aware target preparation
|
|
241
|
-
├── status/ # Cross-target status summary
|
|
242
|
-
│ └── index.ts # Baseline/drift overview
|
|
243
|
-
├── LICENSE
|
|
244
|
-
└── README.md
|
|
245
|
-
```
|
|
71
|
+
OpenUISpec includes an **MCP server** that AI assistants call automatically during UI work — no manual prompting needed.
|
|
246
72
|
|
|
247
|
-
## File formats and schemas
|
|
248
|
-
|
|
249
|
-
Every file type has a corresponding JSON Schema in `schema/`. **Read the schema before creating or editing a file** — do not guess the structure.
|
|
250
|
-
|
|
251
|
-
| File | Schema | Root key | Example |
|
|
252
|
-
|------|--------|----------|---------|
|
|
253
|
-
| `openuispec.yaml` | `openuispec.schema.json` | `spec_version` | [openuispec.yaml](./examples/taskflow/openuispec/openuispec.yaml) |
|
|
254
|
-
| `screens/*.yaml` | `screen.schema.json` | `<screen_id>` | [home.yaml](./examples/taskflow/openuispec/screens/home.yaml) |
|
|
255
|
-
| `flows/*.yaml` | `flow.schema.json` | `<flow_id>` | [create_task.yaml](./examples/taskflow/openuispec/flows/create_task.yaml) |
|
|
256
|
-
| `platform/*.yaml` | `platform.schema.json` | `platform` | [ios.yaml](./examples/taskflow/openuispec/platform/ios.yaml) |
|
|
257
|
-
| `locales/*.json` | `locale.schema.json` | (object) | [en.json](./examples/taskflow/openuispec/locales/en.json) |
|
|
258
|
-
| `contracts/<name>.yaml` | `contract.schema.json` | `<contract_name>` | [input_field.yaml](./examples/taskflow/openuispec/contracts/input_field.yaml) |
|
|
259
|
-
| `contracts/x_*.yaml` | `custom-contract.schema.json` | `<x_name>` | [x_media_player.yaml](./examples/taskflow/openuispec/contracts/x_media_player.yaml) |
|
|
260
|
-
| `tokens/color.yaml` | `tokens/color.schema.json` | `color` | [color.yaml](./examples/taskflow/openuispec/tokens/color.yaml) |
|
|
261
|
-
| `tokens/typography.yaml` | `tokens/typography.schema.json` | `typography` | [typography.yaml](./examples/taskflow/openuispec/tokens/typography.yaml) |
|
|
262
|
-
| `tokens/spacing.yaml` | `tokens/spacing.schema.json` | `spacing` | [spacing.yaml](./examples/taskflow/openuispec/tokens/spacing.yaml) |
|
|
263
|
-
| `tokens/elevation.yaml` | `tokens/elevation.schema.json` | `elevation` | [elevation.yaml](./examples/taskflow/openuispec/tokens/elevation.yaml) |
|
|
264
|
-
| `tokens/motion.yaml` | `tokens/motion.schema.json` | `motion` | [motion.yaml](./examples/taskflow/openuispec/tokens/motion.yaml) |
|
|
265
|
-
| `tokens/layout.yaml` | `tokens/layout.schema.json` | `layout` | [layout.yaml](./examples/taskflow/openuispec/tokens/layout.yaml) |
|
|
266
|
-
| `tokens/themes.yaml` | `tokens/themes.schema.json` | `themes` | [themes.yaml](./examples/taskflow/openuispec/tokens/themes.yaml) |
|
|
267
|
-
| `tokens/icons.yaml` | `tokens/icons.schema.json` | `icons` | [icons.yaml](./examples/taskflow/openuispec/tokens/icons.yaml) |
|
|
268
|
-
|
|
269
|
-
Every token file **must** have a single root wrapper key matching its type:
|
|
270
|
-
|
|
271
|
-
```yaml
|
|
272
|
-
# Correct — tokens/color.yaml
|
|
273
|
-
color:
|
|
274
|
-
brand:
|
|
275
|
-
primary: ...
|
|
276
|
-
|
|
277
|
-
# Wrong — missing root key
|
|
278
|
-
brand:
|
|
279
|
-
primary: ...
|
|
280
73
|
```
|
|
281
|
-
|
|
282
|
-
Validate with: `openuispec validate`
|
|
283
|
-
|
|
284
|
-
Use `openuispec validate semantic` to run cross-reference linting for locale keys, formatter refs, mapper refs, contracts, icons, navigation targets, and API endpoint references.
|
|
285
|
-
|
|
286
|
-
### Shared interactive state roles
|
|
287
|
-
|
|
288
|
-
Interactive contracts may optionally express state-specific visual roles inside their token maps with a nested `states:` object. This lets generators use explicit foreground/background/icon/border roles for `default`, `active`, `selected`, `pressed`, `focused`, `disabled`, `loading`, and `error` states instead of inferring them from container colors or platform defaults.
|
|
289
|
-
|
|
290
|
-
Allowed visual role keys (no others are permitted):
|
|
291
|
-
|
|
292
|
-
- `background`
|
|
293
|
-
- `text`
|
|
294
|
-
- `icon`
|
|
295
|
-
- `border`
|
|
296
|
-
- `badge_background`
|
|
297
|
-
- `badge_text`
|
|
298
|
-
|
|
299
|
-
When `states:` is omitted, generators fall back to the token values defined at that level plus the base contract semantics.
|
|
300
|
-
|
|
301
|
-
## Output directories
|
|
302
|
-
|
|
303
|
-
By default, drift stores state in `generated/<target>/<project>/`. To point targets to your actual code directories, add `output_dir` to `openuispec.yaml`:
|
|
304
|
-
|
|
305
|
-
```yaml
|
|
306
|
-
generation:
|
|
307
|
-
targets: [ios, android, web]
|
|
308
|
-
extra_rules:
|
|
309
|
-
- "Generation hint strings may start with [common], [ios], [android], or [web] to indicate scope."
|
|
310
|
-
output_dir:
|
|
311
|
-
web: "../web-ui/"
|
|
312
|
-
android: "../kmp-ui/"
|
|
313
|
-
ios: "../kmp-ui/iosApp/"
|
|
314
|
-
code_roots:
|
|
315
|
-
backend: "../api/"
|
|
74
|
+
openuispec init → configures MCP for your agent → AI calls tools automatically
|
|
316
75
|
```
|
|
317
76
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
If `api.endpoints` are declared, `generation.code_roots.backend` is required. It should point at the backend folder the AI must inspect when generating API clients or wiring request/response behavior.
|
|
321
|
-
|
|
322
|
-
`generation.extra_rules` can hold project-wide generation conventions for AI and humans. For example, projects may declare that generation hint strings use prefixes such as `[common]`, `[ios]`, `[android]`, and `[web]` to indicate scope.
|
|
323
|
-
|
|
324
|
-
`openuispec drift --snapshot --target <target>` requires that target output directory to already exist. If it does not, generate the target code first, then snapshot the accepted baseline.
|
|
325
|
-
|
|
326
|
-
Use the commands like this:
|
|
327
|
-
- `openuispec validate` checks schema correctness
|
|
328
|
-
- `openuispec validate semantic` checks cross-references such as locale keys, formatters, mappers, contracts, icons, navigation targets, and API endpoints
|
|
329
|
-
- `openuispec init --no-configure-targets` scaffolds the spec project without running the target-stack wizard
|
|
330
|
-
- `openuispec configure-target <t>` records and confirms target stack choices in `platform/<target>.yaml`, while still allowing custom framework/library values when the project uses something outside the catalog
|
|
331
|
-
- `openuispec drift --target <t> --explain` explains semantic spec changes since that target's accepted baseline
|
|
332
|
-
- `openuispec prepare --target <t>` builds the target work bundle for either first-time generation or drift-based updates
|
|
333
|
-
- `openuispec status` shows every target's snapshot state, baseline commit, and whether that target is behind the current spec, still needs a baseline, or has not been generated yet
|
|
77
|
+
When you ask your AI to "add a settings page" or "update the home feed," the MCP server provides spec context before generation, feeds authoritative spec contents during generation, and returns a concrete audit checklist after generation.
|
|
334
78
|
|
|
335
|
-
|
|
336
|
-
- `openuispec read-specs [paths...]` reads spec file contents as JSON
|
|
337
|
-
- `openuispec get-screen <name>` gets a single screen spec
|
|
338
|
-
- `openuispec get-contract <name> [--variant v]` gets a contract spec, optionally one variant
|
|
339
|
-
- `openuispec get-tokens <category>` gets tokens for a category (color, typography, spacing, etc.)
|
|
340
|
-
- `openuispec get-locale <locale> [--keys k1,k2]` gets a locale file, optionally filtered keys
|
|
341
|
-
- `openuispec spec-types` lists all available spec types with descriptions
|
|
342
|
-
- `openuispec spec-schema <type>` gets the full JSON schema for a spec type
|
|
79
|
+
15 tools are available as both MCP tools and CLI commands — see the [full reference](./docs/cli.md).
|
|
343
80
|
|
|
344
|
-
|
|
345
|
-
- `openuispec screenshot --route /path [--theme dark] [--output-dir dir]` screenshots the web app
|
|
346
|
-
- `openuispec screenshot-android [--project-dir path] [--screen name] [--module name]` screenshots the Android app on an emulator
|
|
347
|
-
- `openuispec screenshot-ios [--project-dir path] [--screen name] [--scheme name]` screenshots the iOS app on a Simulator
|
|
81
|
+
**Using without MCP?** You can provide spec context to any AI manually:
|
|
348
82
|
|
|
349
|
-
|
|
83
|
+
> Generate a native iOS app from this OpenUISpec. Follow all contract state machines, apply token ranges for iOS, and implement navigation flows as defined.
|
|
350
84
|
|
|
351
|
-
|
|
85
|
+
## Examples
|
|
352
86
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
- iOS
|
|
87
|
+
| Example | Targets | What it demonstrates |
|
|
88
|
+
|---------|---------|---------------------|
|
|
89
|
+
| [TaskFlow](./examples/taskflow/openuispec/) | iOS, Android, Web | Compact reference covering all 7 contract families |
|
|
90
|
+
| [Todo Orbit](./examples/todo-orbit/openuispec/) | iOS, Android, Web | Bilingual task app with localization, custom contracts |
|
|
91
|
+
| [Social App](./examples/social-app/openuispec/) | Android, Web | Trilingual social app with feeds, messaging, profiles |
|
|
357
92
|
|
|
358
|
-
|
|
93
|
+
## Documentation
|
|
359
94
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
```bash
|
|
367
|
-
openuispec validate
|
|
368
|
-
openuispec validate semantic
|
|
369
|
-
openuispec status
|
|
370
|
-
openuispec drift --target ios --explain
|
|
371
|
-
openuispec prepare --target ios
|
|
372
|
-
# update the ios implementation
|
|
373
|
-
# ensure the ios output directory already exists
|
|
374
|
-
openuispec drift --snapshot --target ios
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
Meaning:
|
|
378
|
-
- `validate` checks schema correctness
|
|
379
|
-
- `validate semantic` checks cross-reference integrity
|
|
380
|
-
- `status` shows which targets are up to date, need a baseline, or still need generation
|
|
381
|
-
- `drift --explain` shows semantic spec changes since that target's accepted baseline
|
|
382
|
-
- `prepare` packages the target work bundle for AI/developers. It runs in `bootstrap` mode for first-time generation and `update` mode after a target snapshot exists.
|
|
383
|
-
- `drift --snapshot` accepts the updated state after the target UI has been updated and the target output directory exists
|
|
384
|
-
|
|
385
|
-
Before picking the next platform to update, run:
|
|
386
|
-
|
|
387
|
-
```bash
|
|
388
|
-
openuispec status
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
to see which targets are already up to date and which ones still need to catch up with shared spec changes.
|
|
392
|
-
|
|
393
|
-
`drift --snapshot` is bookkeeping. It does not prove that the target code matches the spec, and it will not create a missing target output directory for you.
|
|
394
|
-
|
|
395
|
-
## Spec at a glance
|
|
396
|
-
|
|
397
|
-
| Section | What it defines |
|
|
398
|
-
|---------|----------------|
|
|
399
|
-
| 1. Philosophy | Core principles: semantic, constrained, contract-driven, AI-first |
|
|
400
|
-
| 2. Document structure | Project layout and root manifest |
|
|
401
|
-
| 3. Token layer | Color, typography, spacing, elevation, motion, layout, themes, icons |
|
|
402
|
-
| 4. Component contracts | 7 behavioral families (action_trigger, data_display, input_field, nav_container, feedback, surface, collection) |
|
|
403
|
-
| 5. Screen composition | Contract-based layouts, screen-level keys, adaptive layout system |
|
|
404
|
-
| 6. Navigation flows | Multi-screen journeys with transitions and progress |
|
|
405
|
-
| 7. Platform adaptation | Per-target overrides for iOS, Android, Web |
|
|
406
|
-
| 8. AI generation contract | Compliance levels (MUST/SHOULD/MAY), validation, drift detection |
|
|
407
|
-
| 9. Action system | 14 action types, composition, optimistic updates |
|
|
408
|
-
| 10. Data binding & state | Sources, paths, format expressions, reactivity, caching |
|
|
409
|
-
| 11. Internationalization | Locale files, `$t:` references, ICU MessageFormat, RTL, platform mapping |
|
|
410
|
-
| 12. Custom contract extensions | `x_` prefixed domain-specific contracts, registration, dependencies |
|
|
411
|
-
| 13. Form validation & field dependencies | Validation rules, field dependencies, cross-field checks, async validation |
|
|
412
|
-
| 14. Development workflow | Dual-workflow model, drift detection, spec as sync layer |
|
|
413
|
-
|
|
414
|
-
## The 7 contract families
|
|
415
|
-
|
|
416
|
-
| Contract | Role | Maps to |
|
|
417
|
-
|----------|------|---------|
|
|
418
|
-
| `action_trigger` | Initiates actions | Button, FAB, link |
|
|
419
|
-
| `data_display` | Shows read-only info | Card, list item, stat |
|
|
420
|
-
| `input_field` | Captures user input | TextField, toggle, picker |
|
|
421
|
-
| `nav_container` | Persistent navigation | Tab bar, sidebar, drawer |
|
|
422
|
-
| `feedback` | System status messages | Toast, dialog, banner |
|
|
423
|
-
| `surface` | Contains other components | Sheet, modal, popover |
|
|
424
|
-
| `collection` | Repeating data sets | List, grid, table |
|
|
95
|
+
| Doc | What's in it |
|
|
96
|
+
|-----|-------------|
|
|
97
|
+
| [CLI & MCP Tools](./docs/cli.md) | All CLI commands, MCP tools, screenshot params, target workflow |
|
|
98
|
+
| [File Formats & Schemas](./docs/file-formats.md) | File types, JSON schemas, output directories, spec sections |
|
|
99
|
+
| [Full Specification](./spec/openuispec-v0.1.md) | Complete v0.1 spec (14 sections) |
|
|
100
|
+
| [llms-full.txt](https://openuispec.rsteam.uz/llms-full.txt) | Spec + all schemas in one file (for AI consumption) |
|
|
425
101
|
|
|
426
102
|
## Status
|
|
427
103
|
|
|
428
|
-
**v0.1 — Draft**. The spec covers all foundational layers
|
|
104
|
+
**v0.1 — Draft**. The spec covers all foundational layers with three example apps demonstrating generation across iOS, Android, and Web.
|
|
429
105
|
|
|
430
106
|
### Roadmap
|
|
431
107
|
|
|
432
|
-
- [x] Token system
|
|
433
|
-
- [x]
|
|
434
|
-
- [x]
|
|
435
|
-
- [x]
|
|
436
|
-
- [x]
|
|
437
|
-
- [x] Format expression grammar with computed expressions
|
|
438
|
-
- [x] Internationalization (i18n) with ICU MessageFormat and `$t:` references
|
|
439
|
-
- [x] JSON Schema for spec validation
|
|
440
|
-
- [x] Custom contract extension mechanism
|
|
441
|
-
- [x] Icon system definition
|
|
442
|
-
- [x] Form system (validation rules, field dependencies)
|
|
443
|
-
- [x] Drift detection (spec change tracking per platform)
|
|
444
|
-
- [x] CLI tool (`openuispec init` for project scaffolding + AI rules)
|
|
445
|
-
- [x] MCP server for AI tool integration (`openuispec-mcp`)
|
|
446
|
-
- [x] Multi-platform showcase app (`examples/todo-orbit/`)
|
|
447
|
-
- [x] Social app example (`examples/social-app/`)
|
|
108
|
+
- [x] Token system, 7 contract families, adaptive layout, action system
|
|
109
|
+
- [x] Data binding, i18n, form validation, custom contract extensions
|
|
110
|
+
- [x] JSON Schema validation, CLI tool, MCP server
|
|
111
|
+
- [x] Drift detection, visual verification (screenshots)
|
|
112
|
+
- [x] Example apps: TaskFlow, Todo Orbit, Social App
|
|
448
113
|
- [ ] More example apps (e-commerce, dashboard)
|
|
449
114
|
|
|
450
115
|
## Contributing
|
package/cli/init.ts
CHANGED
|
@@ -558,7 +558,7 @@ const JSON_MCP_PATHS = [
|
|
|
558
558
|
const CODEX_CONFIG_PATH = join(".codex", "config.toml");
|
|
559
559
|
const CODEX_MCP_BLOCK = `\n[mcp_servers.openuispec]\ncommand = "openuispec"\nargs = ["mcp"]\n`;
|
|
560
560
|
|
|
561
|
-
function configureCodexMcp(cwd: string, quiet: boolean):
|
|
561
|
+
function configureCodexMcp(cwd: string, quiet: boolean): boolean {
|
|
562
562
|
const codexDir = join(cwd, ".codex");
|
|
563
563
|
|
|
564
564
|
const configPath = join(codexDir, "config.toml");
|
|
@@ -572,18 +572,22 @@ function configureCodexMcp(cwd: string, quiet: boolean): void {
|
|
|
572
572
|
|
|
573
573
|
if (content.includes("[mcp_servers.openuispec]")) {
|
|
574
574
|
if (!quiet) console.log(` skip ${CODEX_CONFIG_PATH} (openuispec MCP already configured)`);
|
|
575
|
-
return;
|
|
575
|
+
return false;
|
|
576
576
|
}
|
|
577
577
|
|
|
578
578
|
if (!existsSync(codexDir)) mkdirSync(codexDir);
|
|
579
579
|
writeFileSync(configPath, content + CODEX_MCP_BLOCK);
|
|
580
580
|
if (!quiet) console.log(` ${content ? "update" : "create"} ${CODEX_CONFIG_PATH} (MCP server configured)`);
|
|
581
|
+
return true;
|
|
581
582
|
} catch {
|
|
582
583
|
if (!quiet) console.log(` skip ${CODEX_CONFIG_PATH} (could not configure MCP server)`);
|
|
584
|
+
return false;
|
|
583
585
|
}
|
|
584
586
|
}
|
|
585
587
|
|
|
586
588
|
function configureMcp(cwd: string, showRestart: boolean, quiet: boolean = false): void {
|
|
589
|
+
let changed = false;
|
|
590
|
+
|
|
587
591
|
for (const relPath of JSON_MCP_PATHS) {
|
|
588
592
|
const configPath = join(cwd, relPath);
|
|
589
593
|
|
|
@@ -611,6 +615,7 @@ function configureMcp(cwd: string, showRestart: boolean, quiet: boolean = false)
|
|
|
611
615
|
config.mcpServers.openuispec = { ...EXPECTED_MCP_CONFIG };
|
|
612
616
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
613
617
|
if (!quiet) console.log(` ${existing ? "update" : "create"} ${relPath} (MCP server configured)`);
|
|
618
|
+
changed = true;
|
|
614
619
|
} else {
|
|
615
620
|
if (!quiet) console.log(` skip ${relPath} (openuispec MCP already configured)`);
|
|
616
621
|
}
|
|
@@ -620,9 +625,9 @@ function configureMcp(cwd: string, showRestart: boolean, quiet: boolean = false)
|
|
|
620
625
|
}
|
|
621
626
|
|
|
622
627
|
// Codex: .codex/config.toml (TOML format)
|
|
623
|
-
configureCodexMcp(cwd, quiet);
|
|
628
|
+
if (configureCodexMcp(cwd, quiet)) changed = true;
|
|
624
629
|
|
|
625
|
-
if (showRestart) console.log(`\n Restart your AI coding agent to activate the MCP server.`);
|
|
630
|
+
if (showRestart && changed) console.log(`\n Restart your AI coding agent to activate the MCP server.`);
|
|
626
631
|
|
|
627
632
|
// Clean up stale .claude.json MCP config from older versions
|
|
628
633
|
const claudeJsonPath = join(cwd, ".claude.json");
|
package/docs/cli.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# CLI & MCP Tools Reference
|
|
2
|
+
|
|
3
|
+
All MCP tools have equivalent CLI commands. The MCP server is used by AI coding agents automatically; the CLI is for manual use and scripts.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
`openuispec init` and `openuispec update-rules` automatically configure MCP for all supported agents:
|
|
8
|
+
|
|
9
|
+
| Agent | Config file | Created automatically |
|
|
10
|
+
|-------|------------|----------------------|
|
|
11
|
+
| **Claude Code** | `.mcp.json` | Always |
|
|
12
|
+
| **Codex** | `.codex/config.toml` | Always |
|
|
13
|
+
| **VS Code / Copilot** | `.vscode/mcp.json` | If `.vscode/` exists |
|
|
14
|
+
| **Gemini CLI** | `.gemini/settings.json` | If `.gemini/` exists |
|
|
15
|
+
|
|
16
|
+
Manual setup (if needed):
|
|
17
|
+
|
|
18
|
+
**Claude Code** (`.mcp.json`), **VS Code / Copilot** (`.vscode/mcp.json`), **Gemini CLI** (`.gemini/settings.json`):
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"mcpServers": {
|
|
22
|
+
"openuispec": {
|
|
23
|
+
"command": "openuispec",
|
|
24
|
+
"args": ["mcp"]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Codex** (`.codex/config.toml`):
|
|
31
|
+
```toml
|
|
32
|
+
[mcp_servers.openuispec]
|
|
33
|
+
command = "openuispec"
|
|
34
|
+
args = ["mcp"]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Or run directly: `openuispec mcp`
|
|
38
|
+
|
|
39
|
+
## MCP Tools
|
|
40
|
+
|
|
41
|
+
| Tool | When | What it does |
|
|
42
|
+
|------|------|-------------|
|
|
43
|
+
| `openuispec_spec_types` | Before creating spec files | Lists all available spec types with descriptions |
|
|
44
|
+
| `openuispec_spec_schema` | Before creating/editing spec files | Returns the full JSON schema for a specific spec type |
|
|
45
|
+
| `openuispec_prepare` | Before UI code generation | Returns spec context, platform config, generation constraints |
|
|
46
|
+
| `openuispec_read_specs` | Before and after generation | Loads spec file contents — the authoritative source |
|
|
47
|
+
| `openuispec_check` | After generation | Schema validation + concrete audit checklist. Optional `screens`/`contracts` params scope the audit |
|
|
48
|
+
| `openuispec_validate` | After spec edits | Schema-only validation, optionally filtered by group |
|
|
49
|
+
| `openuispec_drift` | Before updates | Detect spec drift since last snapshot, with semantic explanation |
|
|
50
|
+
| `openuispec_status` | Anytime | Cross-target summary: baselines, drift, next steps |
|
|
51
|
+
| `openuispec_get_screen` | Incremental edits | Get a single screen spec by name |
|
|
52
|
+
| `openuispec_get_contract` | Incremental edits | Get a single contract spec, optionally filtered to one variant |
|
|
53
|
+
| `openuispec_get_tokens` | Incremental edits | Get tokens for a specific category |
|
|
54
|
+
| `openuispec_get_locale` | Incremental edits | Get a single locale file, optionally filtered to specific keys |
|
|
55
|
+
| `openuispec_screenshot` | Visual verification | Screenshot the web app at a route via headless browser |
|
|
56
|
+
| `openuispec_screenshot_android` | Visual verification | Screenshot Android app on emulator. Works with any project via `project_dir` |
|
|
57
|
+
| `openuispec_screenshot_ios` | Visual verification | Screenshot iOS app on Simulator via XCUITest. Works with any project via `project_dir` |
|
|
58
|
+
|
|
59
|
+
The server includes **protocol-level instructions** that trigger on UI-related requests independently of CLAUDE.md rules.
|
|
60
|
+
|
|
61
|
+
## CLI Commands
|
|
62
|
+
|
|
63
|
+
### Workflow
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
openuispec init # Scaffold a new spec project
|
|
67
|
+
openuispec init --defaults # Non-interactive with unconfirmed defaults
|
|
68
|
+
openuispec init --no-configure-targets # Skip target stack setup
|
|
69
|
+
openuispec update-rules # Update AI rules to match installed version
|
|
70
|
+
openuispec configure-target <t> [--defaults] # Configure target stack
|
|
71
|
+
openuispec validate [group...] [--json] # Validate spec files
|
|
72
|
+
openuispec validate semantic # Semantic cross-reference linting
|
|
73
|
+
openuispec status [--json] # Cross-target baseline/drift status
|
|
74
|
+
openuispec drift --target <t> --explain # Explain semantic spec drift
|
|
75
|
+
openuispec prepare --target <t> [--json] # Build the target work bundle
|
|
76
|
+
openuispec check --target <t> [--json] # Composite validation + prepare readiness
|
|
77
|
+
openuispec drift --snapshot --target <t> # Snapshot current state + git baseline
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Spec access
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
openuispec read-specs [paths...] # Read spec file contents as JSON
|
|
84
|
+
openuispec get-screen <name> # Get a single screen spec (YAML)
|
|
85
|
+
openuispec get-contract <name> [--variant v] # Get a contract spec
|
|
86
|
+
openuispec get-tokens <category> # Get tokens for a category (YAML)
|
|
87
|
+
openuispec get-locale <locale> [--keys k1,k2] # Get a locale file (JSON)
|
|
88
|
+
openuispec spec-types # List available spec types
|
|
89
|
+
openuispec spec-schema <type> # Get JSON schema for a spec type
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Screenshots
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
openuispec screenshot --route /home [--theme dark] [--output-dir dir]
|
|
96
|
+
openuispec screenshot-android [--project-dir path] [--screen name] [--module name] [--route deeplink]
|
|
97
|
+
openuispec screenshot-ios [--project-dir path] [--screen name] [--scheme name] [--bundle-id id]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Screenshot tools work with **any** project — use `--project-dir` to skip manifest lookup.
|
|
101
|
+
|
|
102
|
+
| Param | Android | iOS | Purpose |
|
|
103
|
+
|-------|---------|-----|---------|
|
|
104
|
+
| `--project-dir` | yes | yes | Point directly at project root |
|
|
105
|
+
| `--module` | yes | -- | Override app module name (default: auto-detect) |
|
|
106
|
+
| `--scheme` | -- | yes | Override Xcode scheme (default: auto-detect) |
|
|
107
|
+
| `--bundle-id` | -- | yes | Override bundle ID (default: auto-detect) |
|
|
108
|
+
| `--route` | yes | -- | Deep link URI for navigation |
|
|
109
|
+
| `--nav` | yes | yes | UI tap steps, comma-separated |
|
|
110
|
+
| `--theme` | yes | yes | Force light or dark mode |
|
|
111
|
+
| `--device` | -- | yes | Simulator device name |
|
|
112
|
+
| `--output-dir` | yes | yes | Save screenshot to directory |
|
|
113
|
+
|
|
114
|
+
## Target Update Workflow
|
|
115
|
+
|
|
116
|
+
When a shared spec change needs to be applied to a target:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
openuispec validate
|
|
120
|
+
openuispec validate semantic
|
|
121
|
+
openuispec status
|
|
122
|
+
openuispec drift --target ios --explain
|
|
123
|
+
openuispec prepare --target ios
|
|
124
|
+
# update the ios implementation
|
|
125
|
+
openuispec drift --snapshot --target ios
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
- `prepare` runs in `bootstrap` mode for first-time generation and `update` mode after a snapshot exists
|
|
129
|
+
- `drift --snapshot` is bookkeeping — it does not prove code matches the spec, and requires the output directory to exist
|
|
130
|
+
- Run `openuispec status` between targets to see what still needs updating
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# File Formats & Schemas
|
|
2
|
+
|
|
3
|
+
Every file type has a corresponding JSON Schema in `schema/`. **Read the schema before creating or editing a file** — do not guess the structure.
|
|
4
|
+
|
|
5
|
+
## File type reference
|
|
6
|
+
|
|
7
|
+
| File | Schema | Root key | Example |
|
|
8
|
+
|------|--------|----------|---------|
|
|
9
|
+
| `openuispec.yaml` | `openuispec.schema.json` | `spec_version` | [openuispec.yaml](../examples/taskflow/openuispec/openuispec.yaml) |
|
|
10
|
+
| `screens/*.yaml` | `screen.schema.json` | `<screen_id>` | [home.yaml](../examples/taskflow/openuispec/screens/home.yaml) |
|
|
11
|
+
| `flows/*.yaml` | `flow.schema.json` | `<flow_id>` | [create_task.yaml](../examples/taskflow/openuispec/flows/create_task.yaml) |
|
|
12
|
+
| `platform/*.yaml` | `platform.schema.json` | `platform` | [ios.yaml](../examples/taskflow/openuispec/platform/ios.yaml) |
|
|
13
|
+
| `locales/*.json` | `locale.schema.json` | (object) | [en.json](../examples/taskflow/openuispec/locales/en.json) |
|
|
14
|
+
| `contracts/<name>.yaml` | `contract.schema.json` | `<contract_name>` | [input_field.yaml](../examples/taskflow/openuispec/contracts/input_field.yaml) |
|
|
15
|
+
| `contracts/x_*.yaml` | `custom-contract.schema.json` | `<x_name>` | [x_media_player.yaml](../examples/taskflow/openuispec/contracts/x_media_player.yaml) |
|
|
16
|
+
| `tokens/color.yaml` | `tokens/color.schema.json` | `color` | [color.yaml](../examples/taskflow/openuispec/tokens/color.yaml) |
|
|
17
|
+
| `tokens/typography.yaml` | `tokens/typography.schema.json` | `typography` | [typography.yaml](../examples/taskflow/openuispec/tokens/typography.yaml) |
|
|
18
|
+
| `tokens/spacing.yaml` | `tokens/spacing.schema.json` | `spacing` | [spacing.yaml](../examples/taskflow/openuispec/tokens/spacing.yaml) |
|
|
19
|
+
| `tokens/elevation.yaml` | `tokens/elevation.schema.json` | `elevation` | [elevation.yaml](../examples/taskflow/openuispec/tokens/elevation.yaml) |
|
|
20
|
+
| `tokens/motion.yaml` | `tokens/motion.schema.json` | `motion` | [motion.yaml](../examples/taskflow/openuispec/tokens/motion.yaml) |
|
|
21
|
+
| `tokens/layout.yaml` | `tokens/layout.schema.json` | `layout` | [layout.yaml](../examples/taskflow/openuispec/tokens/layout.yaml) |
|
|
22
|
+
| `tokens/themes.yaml` | `tokens/themes.schema.json` | `themes` | [themes.yaml](../examples/taskflow/openuispec/tokens/themes.yaml) |
|
|
23
|
+
| `tokens/icons.yaml` | `tokens/icons.schema.json` | `icons` | [icons.yaml](../examples/taskflow/openuispec/tokens/icons.yaml) |
|
|
24
|
+
|
|
25
|
+
Every token file **must** have a single root wrapper key matching its type:
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
# Correct — tokens/color.yaml
|
|
29
|
+
color:
|
|
30
|
+
brand:
|
|
31
|
+
primary: ...
|
|
32
|
+
|
|
33
|
+
# Wrong — missing root key
|
|
34
|
+
brand:
|
|
35
|
+
primary: ...
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Shared interactive state roles
|
|
39
|
+
|
|
40
|
+
Interactive contracts may optionally express state-specific visual roles inside their token maps with a nested `states:` object. This lets generators use explicit roles for `default`, `active`, `selected`, `pressed`, `focused`, `disabled`, `loading`, and `error` states.
|
|
41
|
+
|
|
42
|
+
Allowed visual role keys: `background`, `text`, `icon`, `border`, `badge_background`, `badge_text`.
|
|
43
|
+
|
|
44
|
+
When `states:` is omitted, generators fall back to the token values defined at that level plus the base contract semantics.
|
|
45
|
+
|
|
46
|
+
## Output directories
|
|
47
|
+
|
|
48
|
+
By default, drift stores state in `generated/<target>/<project>/`. To point targets to your actual code directories:
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
generation:
|
|
52
|
+
targets: [ios, android, web]
|
|
53
|
+
output_dir:
|
|
54
|
+
web: "../web-ui/"
|
|
55
|
+
android: "../kmp-ui/"
|
|
56
|
+
ios: "../kmp-ui/iosApp/"
|
|
57
|
+
code_roots:
|
|
58
|
+
backend: "../api/"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Paths are relative to `openuispec.yaml`. The `.openuispec-state.json` file records spec file hashes plus the git baseline commit metadata.
|
|
62
|
+
|
|
63
|
+
- If `api.endpoints` are declared, `generation.code_roots.backend` is required
|
|
64
|
+
- `generation.extra_rules` can hold project-wide generation conventions
|
|
65
|
+
- `drift --snapshot` requires that target output directory to already exist
|
|
66
|
+
|
|
67
|
+
## Spec sections overview
|
|
68
|
+
|
|
69
|
+
| Section | What it defines |
|
|
70
|
+
|---------|----------------|
|
|
71
|
+
| 1. Philosophy | Core principles: semantic, constrained, contract-driven, AI-first |
|
|
72
|
+
| 2. Document structure | Project layout and root manifest |
|
|
73
|
+
| 3. Token layer | Color, typography, spacing, elevation, motion, layout, themes, icons |
|
|
74
|
+
| 4. Component contracts | 7 behavioral families |
|
|
75
|
+
| 5. Screen composition | Contract-based layouts, adaptive layout system |
|
|
76
|
+
| 6. Navigation flows | Multi-screen journeys with transitions and progress |
|
|
77
|
+
| 7. Platform adaptation | Per-target overrides for iOS, Android, Web |
|
|
78
|
+
| 8. AI generation contract | Compliance levels (MUST/SHOULD/MAY), validation, drift detection |
|
|
79
|
+
| 9. Action system | 14 action types, composition, optimistic updates |
|
|
80
|
+
| 10. Data binding & state | Sources, paths, format expressions, reactivity, caching |
|
|
81
|
+
| 11. Internationalization | Locale files, `$t:` references, ICU MessageFormat, RTL |
|
|
82
|
+
| 12. Custom contract extensions | `x_` prefixed domain-specific contracts |
|
|
83
|
+
| 13. Form validation | Validation rules, field dependencies, cross-field checks |
|
|
84
|
+
| 14. Development workflow | Dual-workflow model, drift detection, spec as sync layer |
|
|
@@ -213,18 +213,14 @@ export async function adbExec(adb: string, serial: string, args: string): Promis
|
|
|
213
213
|
// ── emulator storage cleanup ─────────────────────────────────────────
|
|
214
214
|
|
|
215
215
|
export async function cleanEmulatorStorage(adb: string, serial: string): Promise<void> {
|
|
216
|
-
|
|
217
|
-
//
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
await adbShell(adb, serial,
|
|
223
|
-
}
|
|
224
|
-
try {
|
|
225
|
-
// Clear temp files
|
|
226
|
-
await adbShell(adb, serial, `rm -rf /data/local/tmp/*.apk`);
|
|
227
|
-
} catch { /* ignore */ }
|
|
216
|
+
const cmds = [
|
|
217
|
+
`pm trim-caches 2G`, // aggressively trim package cache
|
|
218
|
+
`rm -rf /data/local/tmp/*.apk`, // leftover APKs from previous installs
|
|
219
|
+
`rm -f /sdcard/openuispec_screenshot.png /sdcard/ui_dump.xml /sdcard/screenshot.png`,
|
|
220
|
+
];
|
|
221
|
+
for (const cmd of cmds) {
|
|
222
|
+
try { await adbShell(adb, serial, cmd); } catch { /* ignore */ }
|
|
223
|
+
}
|
|
228
224
|
}
|
|
229
225
|
|
|
230
226
|
// ── build APK ───────────────────────────────────────────────────────
|
|
@@ -269,23 +265,20 @@ export async function installAndLaunch(
|
|
|
269
265
|
appInfo: AppInfo,
|
|
270
266
|
route?: string,
|
|
271
267
|
): Promise<void> {
|
|
272
|
-
//
|
|
273
|
-
await adbExec(adb, serial, `install -r "${apkPath}"`);
|
|
274
|
-
|
|
275
|
-
// Force-stop and clear saved navigation state
|
|
268
|
+
// Force-stop and uninstall to free storage + wipe saved nav state
|
|
276
269
|
await adbShell(adb, serial, `am force-stop ${appInfo.applicationId}`);
|
|
270
|
+
try { await adbShell(adb, serial, `pm uninstall ${appInfo.applicationId}`); } catch { /* not installed */ }
|
|
277
271
|
|
|
278
|
-
//
|
|
279
|
-
|
|
280
|
-
const clearFlags = `-f 0x10008000`;
|
|
272
|
+
// Install fresh (not -r replace, since we uninstalled)
|
|
273
|
+
await adbExec(adb, serial, `install "${apkPath}"`);
|
|
281
274
|
|
|
282
275
|
if (route) {
|
|
283
276
|
await adbShell(adb, serial,
|
|
284
|
-
`am start -W -a android.intent.action.VIEW -d
|
|
277
|
+
`am start -W -a android.intent.action.VIEW -d '${route}' ` +
|
|
285
278
|
`${appInfo.applicationId}/${appInfo.launchActivity}`);
|
|
286
279
|
} else {
|
|
287
280
|
await adbShell(adb, serial,
|
|
288
|
-
`am start -W
|
|
281
|
+
`am start -W -n ${appInfo.applicationId}/${appInfo.launchActivity}`);
|
|
289
282
|
}
|
|
290
283
|
}
|
|
291
284
|
|