@uicontract/skill 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 UIC Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # @uicontract/skill
2
+
3
+ Agent skill files for [UI Contracts](https://github.com/sherifkozman/uicontract).
4
+
5
+ Gives AI coding agents a structured way to discover, target, and interact with UI elements using stable `data-agent-id` selectors instead of fragile CSS classes or text matches.
6
+
7
+ ---
8
+
9
+ ## What's Included
10
+
11
+ | File | Purpose |
12
+ |------|---------|
13
+ | [`SKILL.md`](./SKILL.md) | Full skill definition - commands, patterns, rules |
14
+ | [`references/manifest-schema.md`](./references/manifest-schema.md) | `manifest.json` structure and field reference |
15
+ | [`references/browser-tool-bridge.md`](./references/browser-tool-bridge.md) | Targeting syntax for Playwright, Cypress, agent-browser, Chrome MCP |
16
+ | [`references/workflow-patterns.md`](./references/workflow-patterns.md) | Multi-step automation recipes |
17
+
18
+ ---
19
+
20
+ ## Installation by Agent Type
21
+
22
+ ### Claude (claude.ai / Claude Code)
23
+
24
+ Add to your project's `CLAUDE.md` or global agent instructions:
25
+
26
+ ```markdown
27
+ @uicontract/skill
28
+ ```
29
+
30
+ Or copy `SKILL.md` into your project root and reference it:
31
+
32
+ ```bash
33
+ npx --yes @uicontract/skill install
34
+ ```
35
+
36
+ For Claude Code, add to `.claude/skills/`:
37
+
38
+ ```bash
39
+ npm install -g @uicontract/skill
40
+ # Then in your project:
41
+ cp $(npm root -g)/@uicontract/skill/SKILL.md .claude/skills/uic.md
42
+ ```
43
+
44
+ ### Cursor
45
+
46
+ Add to `.cursor/rules/uic.mdc`:
47
+
48
+ ```bash
49
+ npm install @uicontract/skill
50
+ cp node_modules/@uicontract/skill/SKILL.md .cursor/rules/uic.mdc
51
+ ```
52
+
53
+ ### GitHub Copilot / VS Code
54
+
55
+ Add to `.github/copilot-instructions.md`:
56
+
57
+ ```bash
58
+ npm install @uicontract/skill
59
+ cat node_modules/@uicontract/skill/SKILL.md >> .github/copilot-instructions.md
60
+ ```
61
+
62
+ ### Any AI coding tool
63
+
64
+ The skill is plain Markdown. Copy `SKILL.md` wherever your tool reads agent instructions:
65
+
66
+ ```bash
67
+ npm install @uicontract/skill
68
+ cat node_modules/@uicontract/skill/SKILL.md
69
+ ```
70
+
71
+ ---
72
+
73
+ ## How It Works
74
+
75
+ Once loaded, the skill teaches the agent to:
76
+
77
+ 1. **Check for an existing `manifest.json`** before scanning
78
+ 2. **Use `npx uicontract find`** to locate elements by label or purpose
79
+ 3. **Target elements by `data-agent-id`** instead of CSS selectors or text
80
+ 4. **Run `npx uicontract diff`** to detect breaking UI changes
81
+
82
+ ```bash
83
+ # Agent finds the element:
84
+ npx uicontract find "pause subscription" --json
85
+ # => { "agentId": "settings.billing.pause-subscription.button", ... }
86
+
87
+ # Agent targets it:
88
+ [data-agent-id="settings.billing.pause-subscription.button"]
89
+ ```
90
+
91
+ See [`SKILL.md`](./SKILL.md) for the full command reference and workflow patterns.
92
+
93
+ ---
94
+
95
+ ## License
96
+
97
+ [MIT](../../LICENSE)
package/SKILL.md ADDED
@@ -0,0 +1,223 @@
1
+ ---
2
+ name: uic
3
+ description: Use when automating browser interactions with a web app that has a manifest.json or data-agent-id attributes. Use when the agent needs to find, target, or interact with specific UI elements by name, label, or purpose.
4
+ ---
5
+
6
+ # UI Contracts for Agent Automation
7
+
8
+ UI Contracts makes web app UIs machine-readable with stable hierarchical IDs, so agents can find, target, and interact with any interactive element by name instead of fragile selectors.
9
+
10
+ ## Quick Start
11
+
12
+ ```bash
13
+ npx uicontract scan ./src -o manifest.json
14
+ npx uicontract name manifest.json -o manifest.json
15
+ npx uicontract find "login" --json
16
+ npx uicontract describe <agent-id> --json
17
+ npx uicontract list --type button --json
18
+ npx uicontract diff old.json new.json --json
19
+ ```
20
+
21
+ ## Core Workflow
22
+
23
+ ### 1. Discover
24
+
25
+ Check for an existing `manifest.json` in the project root. If none exists, generate one:
26
+
27
+ ```bash
28
+ npx uicontract scan ./src -o manifest.json
29
+ npx uicontract name manifest.json -o manifest.json
30
+ ```
31
+
32
+ ### 2. Find
33
+
34
+ Search for elements by description. Fuzzy matching is enabled by default:
35
+
36
+ ```bash
37
+ npx uicontract find "pause subscription" --json
38
+ npx uicontract find "pase subscribtion" --json # fuzzy match still finds it
39
+ npx uicontract find "billing" --type button --json
40
+ ```
41
+
42
+ ### 3. Target
43
+
44
+ Use the `agentId` from the find result to target the element in the browser.
45
+
46
+ **agent-browser:**
47
+
48
+ ```bash
49
+ agent-browser find testid "settings.billing.pause-subscription.button" click
50
+ ```
51
+
52
+ **CSS selector (any tool):**
53
+
54
+ ```css
55
+ [data-agent-id="settings.billing.pause-subscription.button"]
56
+ ```
57
+
58
+ **Playwright MCP:** Launch with `--test-id-attribute=data-agent-id`, then use `ref` values from the accessibility snapshot.
59
+
60
+ See [references/browser-tool-bridge.md](references/browser-tool-bridge.md) for all supported tools.
61
+
62
+ ### 4. Verify
63
+
64
+ Compare the current manifest against a baseline to detect breaking changes:
65
+
66
+ ```bash
67
+ npx uicontract diff baseline.json current.json --json
68
+ ```
69
+
70
+ Exit code 1 means breaking changes were found.
71
+
72
+ ## Commands
73
+
74
+ ### Discovery
75
+
76
+ **scan** -- Discover interactive elements in source code.
77
+
78
+ ```bash
79
+ npx uicontract scan <directory> -o manifest.json
80
+ ```
81
+
82
+ | Flag | Description |
83
+ |------|-------------|
84
+ | `-o, --output <path>` | Output file path (default: `manifest.json`) |
85
+ | `--framework <name>` | Force a specific framework parser |
86
+ | `--json` | Write raw JSON to stdout |
87
+ | `--verbose` | Enable debug logging |
88
+
89
+ **name** -- Assign stable hierarchical IDs to discovered elements.
90
+
91
+ ```bash
92
+ npx uicontract name manifest.json -o manifest.json
93
+ ```
94
+
95
+ | Flag | Description |
96
+ |------|-------------|
97
+ | `-o, --output <path>` | Output file path |
98
+ | `--ai` | Use AI-assisted naming for ambiguous elements |
99
+ | `--ai-timeout <ms>` | Timeout for AI naming requests |
100
+
101
+ **annotate** -- Insert `data-agent-id` attributes into source files.
102
+
103
+ ```bash
104
+ npx uicontract annotate manifest.json --dry-run
105
+ npx uicontract annotate manifest.json --write
106
+ ```
107
+
108
+ | Flag | Description |
109
+ |------|-------------|
110
+ | `--dry-run` | Preview patches without modifying files |
111
+ | `--write` | Apply patches to source files |
112
+ | `--backup-dir <path>` | Directory for pre-annotation backups (default: `.uic-backup/`) |
113
+
114
+ ### Query
115
+
116
+ **find** -- Search for elements by description.
117
+
118
+ ```bash
119
+ npx uicontract find <query> --json
120
+ ```
121
+
122
+ | Flag | Description |
123
+ |------|-------------|
124
+ | `--manifest <path>` | Path to manifest file (default: `manifest.json`) |
125
+ | `--type <type>` | Filter by element type (`button`, `input`, `a`, etc.) |
126
+ | `--exact` | Disable fuzzy matching, require exact substring |
127
+ | `--json` | Output as JSON array |
128
+
129
+ **describe** -- Show detailed info for one element.
130
+
131
+ ```bash
132
+ npx uicontract describe <agent-id> --json
133
+ ```
134
+
135
+ | Flag | Description |
136
+ |------|-------------|
137
+ | `--manifest <path>` | Path to manifest file (default: `manifest.json`) |
138
+ | `--json` | Output as JSON object |
139
+
140
+ **list** -- List elements with optional filters.
141
+
142
+ ```bash
143
+ npx uicontract list --json
144
+ ```
145
+
146
+ | Flag | Description |
147
+ |------|-------------|
148
+ | `--manifest <path>` | Path to manifest file (default: `manifest.json`) |
149
+ | `--type <type>` | Filter by element type |
150
+ | `--route <route>` | Filter by route prefix |
151
+ | `--component <name>` | Filter by component name |
152
+ | `--routes` | List all unique routes |
153
+ | `--components` | List all unique component names |
154
+ | `--json` | Output as JSON array |
155
+
156
+ ### Governance
157
+
158
+ **diff** -- Compare two manifests for breaking changes.
159
+
160
+ ```bash
161
+ npx uicontract diff <old-manifest> <new-manifest> --json
162
+ ```
163
+
164
+ | Flag | Description |
165
+ |------|-------------|
166
+ | `--allow-breaking` | Exit 0 even when breaking changes are found |
167
+ | `--json` | Output diff as JSON object |
168
+
169
+ Change categories:
170
+ - **Breaking**: removed elements, renamed agent IDs, changed element types.
171
+ - **Informational**: added elements, changed labels, moved source locations.
172
+
173
+ ## Selector Patterns
174
+
175
+ Use these CSS attribute selectors to target `data-agent-id` values:
176
+
177
+ | Pattern | Syntax | Use Case |
178
+ |---------|--------|----------|
179
+ | Exact | `[data-agent-id="id"]` | Target one specific element |
180
+ | Prefix | `[data-agent-id^="settings.billing."]` | All elements in a section |
181
+ | Substring | `[data-agent-id*="billing"]` | Any element mentioning "billing" |
182
+ | Suffix | `[data-agent-id$=".button"]` | All buttons |
183
+ | Presence | `[data-agent-id]` | Any UI Contracts-annotated element |
184
+
185
+ ## Integration Example
186
+
187
+ UI Contracts + agent-browser, three steps:
188
+
189
+ **Step 1 -- Find the element:**
190
+
191
+ ```bash
192
+ npx uicontract find "pause subscription" --json
193
+ ```
194
+
195
+ **Step 2 -- Navigate to the page:**
196
+
197
+ ```bash
198
+ agent-browser open http://localhost:3000/settings/billing
199
+ ```
200
+
201
+ **Step 3 -- Interact:**
202
+
203
+ ```bash
204
+ agent-browser find testid "settings.billing.pause-subscription.button" click
205
+ ```
206
+
207
+ ## Key Rules
208
+
209
+ - Always use `--json` for machine parsing. The JSON format is stable across versions.
210
+ - Never hardcode CSS selectors when an agent ID is available.
211
+ - Check `conditional: true` elements -- they may not be in the DOM without the right app state.
212
+ - Check `dynamic: true` elements -- their count depends on runtime data.
213
+ - Run `npx uicontract diff` before and after changes to catch regressions.
214
+ - Run `npx uicontract scan` after UI changes to keep the manifest current.
215
+ - Commit the baseline manifest to version control for CI diffing.
216
+
217
+ ## References
218
+
219
+ | File | Contents |
220
+ |------|----------|
221
+ | [references/browser-tool-bridge.md](references/browser-tool-bridge.md) | Tool-specific targeting (agent-browser, Playwright MCP, Chrome MCP, Cypress) |
222
+ | [references/workflow-patterns.md](references/workflow-patterns.md) | Multi-step automation recipes (form fill, nav test, CI regression, annotation pipeline) |
223
+ | [references/manifest-schema.md](references/manifest-schema.md) | Full manifest.json structure, element fields, agent ID format |
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@uicontract/skill",
3
+ "version": "0.1.0",
4
+ "description": "Agent skill files for UIC - makes web app UIs machine-readable for AI coding agents",
5
+ "license": "MIT",
6
+ "author": "UIC Contributors",
7
+ "homepage": "https://github.com/sherifkozman/uicontract",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/sherifkozman/uicontract.git",
11
+ "directory": "packages/skill"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/sherifkozman/uicontract/issues"
15
+ },
16
+ "keywords": [
17
+ "uic",
18
+ "ui-contracts",
19
+ "agent",
20
+ "skill",
21
+ "ai-agent",
22
+ "data-agent-id",
23
+ "manifest",
24
+ "automation",
25
+ "claude",
26
+ "cursor",
27
+ "copilot"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "files": [
33
+ "SKILL.md",
34
+ "references",
35
+ "README.md"
36
+ ]
37
+ }
@@ -0,0 +1,81 @@
1
+ # Browser Tool Bridge
2
+
3
+ UI Contracts annotates source code with `data-agent-id` attributes. This reference documents how to target those attributes from each browser automation tool, bridging the gap between UI Contracts' manifest output and actual browser interactions.
4
+
5
+ ## Tool-Specific Targeting
6
+
7
+ ### agent-browser
8
+
9
+ No configuration needed. Use the `find testid` locator to target elements by their agent ID directly.
10
+
11
+ ```bash
12
+ # Click an element
13
+ agent-browser find testid "settings.billing.pause-subscription.button" click
14
+
15
+ # Fill a form field
16
+ agent-browser find testid "login.login-form.email.input" fill "user@example.com"
17
+
18
+ # Check visibility
19
+ agent-browser find testid "settings.billing.pause-subscription.button" visible
20
+ ```
21
+
22
+ ### Playwright MCP
23
+
24
+ Configure the `--test-id-attribute` flag at launch so Playwright recognizes `data-agent-id` as the test ID attribute:
25
+
26
+ ```bash
27
+ npx playwright --test-id-attribute=data-agent-id
28
+ ```
29
+
30
+ After this configuration, agent IDs appear in accessibility snapshots. Use the `ref` values from the snapshot to interact with elements.
31
+
32
+ ### Chrome MCP
33
+
34
+ Use the `find` tool with a natural-language description, or use `javascript_tool` with a CSS selector for precise targeting:
35
+
36
+ ```javascript
37
+ document.querySelector('[data-agent-id="settings.billing.pause-subscription.button"]')
38
+ ```
39
+
40
+ ### Cypress
41
+
42
+ Target elements with the standard attribute selector:
43
+
44
+ ```javascript
45
+ cy.get('[data-agent-id="settings.billing.pause-subscription.button"]').click()
46
+ cy.get('[data-agent-id="login.login-form.email.input"]').type('user@example.com')
47
+ ```
48
+
49
+ ### Any CSS-Based Tool
50
+
51
+ The universal selector pattern works with any tool that supports CSS selectors:
52
+
53
+ ```css
54
+ [data-agent-id="settings.billing.pause-subscription.button"]
55
+ ```
56
+
57
+ ## Selector Patterns
58
+
59
+ | Pattern | Syntax | Use Case |
60
+ |-----------|-------------------------------------------|---------------------------------------|
61
+ | Exact | `[data-agent-id="id"]` | Target one specific element |
62
+ | Prefix | `[data-agent-id^="settings.billing."]` | All elements in billing section |
63
+ | Substring | `[data-agent-id*="billing"]` | Any element mentioning "billing" |
64
+ | Suffix | `[data-agent-id$=".button"]` | All buttons |
65
+ | Presence | `[data-agent-id]` | Any UI Contracts-annotated element |
66
+
67
+ ## Handling Conditional Elements
68
+
69
+ Elements with `"conditional": true` in the manifest may not be present in the DOM at all times. Before targeting a conditional element:
70
+
71
+ 1. **Check the route.** The manifest's `route` field tells you which page the element lives on. Navigate there first.
72
+ 2. **Wait for render.** After navigation, use the tool's wait or retry mechanism to allow the element to appear.
73
+ 3. **Verify visibility.** Confirm the element is present before interacting. If it is not, the required application state (e.g., a modal being open, a feature flag being enabled) may not be met.
74
+
75
+ ## Handling Dynamic Elements
76
+
77
+ Elements with `"dynamic": true` in the manifest are rendered from data (e.g., a list of items from an API response). The exact set of elements depends on runtime data. To work with dynamic elements:
78
+
79
+ 1. **Use prefix selectors** to discover all instances. For example, `[data-agent-id^="dashboard.task-list.task-"]` matches every task item regardless of how many exist.
80
+ 2. **Enumerate first.** Query all matching elements, then filter or iterate over the results.
81
+ 3. **Expect variability.** The count of dynamic elements will differ between environments and over time as data changes.
@@ -0,0 +1,75 @@
1
+ # Manifest Schema Reference
2
+
3
+ The manifest is a JSON file produced by running `npx uicontract scan <dir>` followed by `npx uicontract name`. It describes every interactive element in a web application, giving each a stable hierarchical ID that browser automation tools can target.
4
+
5
+ ## Top-Level Structure
6
+
7
+ ```jsonc
8
+ {
9
+ "schemaVersion": "1.0",
10
+ "generatedAt": "2026-02-21T00:00:00Z",
11
+ "generator": { "name": "uicontract", "version": "0.1.0" },
12
+ "metadata": {
13
+ "framework": "react",
14
+ "projectRoot": "/path/to/project",
15
+ "filesScanned": 42,
16
+ "elementsDiscovered": 87,
17
+ "warnings": 3
18
+ },
19
+ "elements": [
20
+ { /* ... element objects ... */ }
21
+ ]
22
+ }
23
+ ```
24
+
25
+ | Field | Type | Description |
26
+ |-----------------|--------|------------------------------------------|
27
+ | schemaVersion | string | Schema version, currently `"1.0"` |
28
+ | generatedAt | string | ISO 8601 datetime of manifest generation |
29
+ | generator | object | Tool name and version that produced this |
30
+ | metadata | object | Summary statistics about the scan |
31
+ | elements | array | List of discovered interactive elements |
32
+
33
+ ## Metadata
34
+
35
+ | Field | Type | Example | Description |
36
+ |--------------------|--------|------------|------------------------------------|
37
+ | framework | string | `"react"` | Detected framework (`react`, `vue`) |
38
+ | projectRoot | string | `"/app"` | Absolute path to project root |
39
+ | filesScanned | number | `42` | Number of source files scanned |
40
+ | elementsDiscovered | number | `87` | Total interactive elements found |
41
+ | warnings | number | `3` | Count of parser warnings |
42
+
43
+ ## Element Fields
44
+
45
+ Each object in the `elements` array describes one interactive element:
46
+
47
+ | Field | Type | Description |
48
+ |---------------|----------------|----------------------------------------------------|
49
+ | agentId | string | Stable hierarchical ID -- the primary selector target |
50
+ | type | string | Element kind: `button`, `input`, `select`, `a`, `form`, `textarea` |
51
+ | label | string\|null | Human-readable description of the element |
52
+ | route | string\|null | URL path where the element appears |
53
+ | handler | string\|null | Event handler function name (e.g. `handleSubmit`) |
54
+ | conditional | boolean | `true` if the element may not always be visible |
55
+ | dynamic | boolean | `true` if rendered from dynamic data |
56
+ | filePath | string | Source file path relative to project root |
57
+ | line | number | Line number in source file (1-indexed) |
58
+ | column | number | Column number in source file (1-indexed) |
59
+ | componentName | string\|null | Name of the React/Vue component containing this element |
60
+
61
+ ## Agent ID Format
62
+
63
+ Agent IDs follow the pattern:
64
+
65
+ ```
66
+ route.component.element-name.type
67
+ ```
68
+
69
+ IDs use dot-separated segments with kebab-case within each segment. Examples:
70
+
71
+ - `settings.billing.pause-subscription.button` -- a button in the BillingSettings component on the /settings/billing route
72
+ - `login.login-form.email.input` -- an email input in the LoginForm component on the /login route
73
+ - `dashboard.header.notifications.a` -- a notifications link in the Header component on the /dashboard route
74
+
75
+ The hierarchical structure enables prefix-based selectors. For example, `settings.billing.*` matches every interactive element on the billing settings page, useful for scoping automation tasks to a specific section of the UI.
@@ -0,0 +1,234 @@
1
+ # Workflow Patterns
2
+
3
+ Multi-step automation recipes that chain UI Contracts CLI commands with browser tools. Each recipe is a concrete bash sequence you can adapt to your application.
4
+
5
+ ## Recipe 1: Form Fill
6
+
7
+ Scan the manifest for input fields on a specific route, fill each one, then submit.
8
+
9
+ ### Step 1 -- Discover inputs on the target route
10
+
11
+ ```bash
12
+ npx uicontract list --route "/checkout" --type input --json
13
+ ```
14
+
15
+ Expected output:
16
+
17
+ ```json
18
+ [
19
+ { "agentId": "checkout.shipping-form.first-name.input", "type": "input", "label": "First name" },
20
+ { "agentId": "checkout.shipping-form.last-name.input", "type": "input", "label": "Last name" },
21
+ { "agentId": "checkout.shipping-form.address.input", "type": "input", "label": "Address" },
22
+ { "agentId": "checkout.shipping-form.city.input", "type": "input", "label": "City" },
23
+ { "agentId": "checkout.shipping-form.zip.input", "type": "input", "label": "Zip code" }
24
+ ]
25
+ ```
26
+
27
+ ### Step 2 -- Find the submit button
28
+
29
+ ```bash
30
+ npx uicontract find "submit order" --json
31
+ ```
32
+
33
+ Expected output:
34
+
35
+ ```json
36
+ [
37
+ { "agentId": "checkout.shipping-form.submit-order.button", "type": "button", "label": "Submit order" }
38
+ ]
39
+ ```
40
+
41
+ ### Step 3 -- Navigate and fill
42
+
43
+ ```bash
44
+ # Navigate to the checkout page
45
+ agent-browser navigate "https://localhost:3000/checkout"
46
+
47
+ # Fill each field using the agent IDs from Step 1
48
+ agent-browser find testid "checkout.shipping-form.first-name.input" fill "Jane"
49
+ agent-browser find testid "checkout.shipping-form.last-name.input" fill "Doe"
50
+ agent-browser find testid "checkout.shipping-form.address.input" fill "123 Main St"
51
+ agent-browser find testid "checkout.shipping-form.city.input" fill "Springfield"
52
+ agent-browser find testid "checkout.shipping-form.zip.input" fill "62704"
53
+
54
+ # Submit
55
+ agent-browser find testid "checkout.shipping-form.submit-order.button" click
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Recipe 2: Navigation Test
61
+
62
+ Verify that every route in the application has the expected interactive elements present and visible.
63
+
64
+ ### Step 1 -- Get all routes
65
+
66
+ ```bash
67
+ npx uicontract list --routes --json
68
+ ```
69
+
70
+ Expected output:
71
+
72
+ ```json
73
+ [
74
+ "/",
75
+ "/login",
76
+ "/dashboard",
77
+ "/settings/billing",
78
+ "/checkout"
79
+ ]
80
+ ```
81
+
82
+ ### Step 2 -- Get elements per route
83
+
84
+ For each route, list the elements expected on that page:
85
+
86
+ ```bash
87
+ npx uicontract list --route "/login" --json
88
+ ```
89
+
90
+ Expected output:
91
+
92
+ ```json
93
+ [
94
+ { "agentId": "login.login-form.email.input", "type": "input", "label": "Email" },
95
+ { "agentId": "login.login-form.password.input", "type": "input", "label": "Password" },
96
+ { "agentId": "login.login-form.sign-in.button", "type": "button", "label": "Sign in" }
97
+ ]
98
+ ```
99
+
100
+ ### Step 3 -- Navigate and verify each route
101
+
102
+ ```bash
103
+ # For each route, navigate and confirm every non-conditional element is visible
104
+ agent-browser navigate "https://localhost:3000/login"
105
+
106
+ agent-browser find testid "login.login-form.email.input" visible
107
+ agent-browser find testid "login.login-form.password.input" visible
108
+ agent-browser find testid "login.login-form.sign-in.button" visible
109
+ ```
110
+
111
+ Repeat for every route. Skip elements with `"conditional": true` unless you set up the required application state first (see Browser Tool Bridge for conditional element handling).
112
+
113
+ ---
114
+
115
+ ## Recipe 3: Regression Check (CI)
116
+
117
+ Compare a baseline manifest against the current source to detect breaking changes. Intended for CI pipelines.
118
+
119
+ ### Step 1 -- Generate the current manifest
120
+
121
+ ```bash
122
+ npx uicontract scan ./src -o current.json && npx uicontract name current.json -o current.json
123
+ ```
124
+
125
+ ### Step 2 -- Diff against baseline
126
+
127
+ ```bash
128
+ npx uicontract diff baseline.json current.json --json
129
+ ```
130
+
131
+ Expected output when there are no breaking changes:
132
+
133
+ ```json
134
+ {
135
+ "breaking": [],
136
+ "nonBreaking": [
137
+ { "type": "added", "agentId": "settings.profile.avatar-upload.input" }
138
+ ],
139
+ "summary": { "breaking": 0, "nonBreaking": 1 }
140
+ }
141
+ ```
142
+
143
+ Expected output when there are breaking changes:
144
+
145
+ ```json
146
+ {
147
+ "breaking": [
148
+ { "type": "removed", "agentId": "checkout.shipping-form.submit-order.button" },
149
+ { "type": "renamed", "oldAgentId": "login.login-form.sign-in.button", "newAgentId": "login.auth-form.log-in.button" }
150
+ ],
151
+ "nonBreaking": [],
152
+ "summary": { "breaking": 2, "nonBreaking": 0 }
153
+ }
154
+ ```
155
+
156
+ ### Step 3 -- Fail CI on breaking changes
157
+
158
+ ```bash
159
+ npx uicontract diff baseline.json current.json --json
160
+ EXIT_CODE=$?
161
+
162
+ if [ $EXIT_CODE -ne 0 ]; then
163
+ echo "Breaking manifest changes detected. Review the diff output above."
164
+ echo "If intentional, update baseline.json: cp current.json baseline.json"
165
+ exit 1
166
+ fi
167
+ ```
168
+
169
+ `uicontract diff` exits with code 1 when breaking changes are found, making it a direct CI gate.
170
+
171
+ ---
172
+
173
+ ## Recipe 4: Full Annotation Pipeline
174
+
175
+ Scan the source, generate stable names, annotate source files with `data-agent-id` attributes, then verify the round-trip produces a stable manifest.
176
+
177
+ ### Step 1 -- Scan
178
+
179
+ ```bash
180
+ npx uicontract scan ./src -o manifest.json
181
+ ```
182
+
183
+ ### Step 2 -- Name
184
+
185
+ ```bash
186
+ npx uicontract name manifest.json -o manifest.json
187
+ ```
188
+
189
+ ### Step 3 -- Preview annotations (dry run)
190
+
191
+ ```bash
192
+ npx uicontract annotate manifest.json --dry-run
193
+ ```
194
+
195
+ Expected output shows the patches that would be applied:
196
+
197
+ ```
198
+ src/components/LoginForm.tsx:12:8
199
+ - <input type="email" />
200
+ + <input type="email" data-agent-id="login.login-form.email.input" />
201
+
202
+ src/components/LoginForm.tsx:18:8
203
+ - <button onClick={handleSubmit}>Sign in</button>
204
+ + <button onClick={handleSubmit} data-agent-id="login.login-form.sign-in.button">Sign in</button>
205
+
206
+ 2 files, 5 elements to annotate.
207
+ ```
208
+
209
+ ### Step 4 -- Write annotations
210
+
211
+ ```bash
212
+ npx uicontract annotate manifest.json --write
213
+ ```
214
+
215
+ This modifies source files in place. A backup is created in `.uic-backup/` before any changes are written.
216
+
217
+ ### Step 5 -- Re-scan and verify round-trip
218
+
219
+ ```bash
220
+ npx uicontract scan ./src -o manifest-after.json && npx uicontract name manifest-after.json -o manifest-after.json
221
+ npx uicontract diff manifest.json manifest-after.json --json
222
+ ```
223
+
224
+ Expected output for a successful round-trip (zero changes):
225
+
226
+ ```json
227
+ {
228
+ "breaking": [],
229
+ "nonBreaking": [],
230
+ "summary": { "breaking": 0, "nonBreaking": 0 }
231
+ }
232
+ ```
233
+
234
+ A zero-change diff confirms that annotations were inserted correctly and the re-scan produces the same manifest. If the diff reports changes, the annotator may have altered element positions or the parser may be interpreting annotated source differently than unannotated source -- both are bugs worth investigating.