opencode-skills-collection 4.1.18 → 4.1.20
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/bundled-skills/.antigravity-install-manifest.json +20 -1
- package/bundled-skills/ai-headshot-studio/SKILL.md +107 -99
- package/bundled-skills/ai-image-generation-studio/SKILL.md +108 -93
- package/bundled-skills/ai-logo-maker/SKILL.md +108 -93
- package/bundled-skills/ai-multilingual-dubbing/SKILL.md +108 -93
- package/bundled-skills/ai-photo-restyler/SKILL.md +108 -93
- package/bundled-skills/ai-podcast-voiceover/SKILL.md +108 -93
- package/bundled-skills/aident-loadout/SKILL.md +88 -0
- package/bundled-skills/antigravity-maintainer-batch-release/SKILL.md +27 -254
- package/bundled-skills/antigravity-maintainer-batch-release/agents/openai.yaml +1 -1
- package/bundled-skills/antigravity-maintainer-batch-release/references/component-validation.md +18 -0
- package/bundled-skills/antigravity-maintainer-batch-release/references/core-preview.md +20 -0
- package/bundled-skills/antigravity-maintainer-batch-release/references/maintenance-contract.md +83 -0
- package/bundled-skills/antigravity-maintainer-batch-release/references/maintenance-cycle.md +149 -0
- package/bundled-skills/antigravity-maintainer-batch-release/references/public-surfaces.md +22 -0
- package/bundled-skills/antigravity-maintainer-batch-release/references/skillspector.md +40 -0
- package/bundled-skills/apify-facebook-ads-library-scraper/SKILL.md +197 -0
- package/bundled-skills/apify-facebook-ads-library-scraper/references/gotchas.md +45 -0
- package/bundled-skills/apify-linkedin-jobs-scraper/SKILL.md +181 -0
- package/bundled-skills/apify-linkedin-jobs-scraper/references/gotchas.md +57 -0
- package/bundled-skills/apify-tiktok-scraper/SKILL.md +199 -0
- package/bundled-skills/apify-tiktok-scraper/references/gotchas.md +45 -0
- package/bundled-skills/arcmira-find-quotes/SKILL.md +5 -0
- package/bundled-skills/beatra/SKILL.md +109 -90
- package/bundled-skills/beatra-ai-video-studio/SKILL.md +110 -90
- package/bundled-skills/curlshot/SKILL.md +139 -0
- package/bundled-skills/datacircle/SKILL.md +159 -98
- package/bundled-skills/deed-page/SKILL.md +161 -0
- package/bundled-skills/design-token-contrast/SKILL.md +128 -0
- package/bundled-skills/design-token-contrast/references/contraste-checker.md +330 -0
- package/bundled-skills/ecommerce-listing-image-set/SKILL.md +109 -90
- package/bundled-skills/goal-instruction-writer/LICENSE +21 -0
- package/bundled-skills/goal-instruction-writer/SKILL.md +275 -0
- package/bundled-skills/goal-instruction-writer/references/contribution-walkthrough.md +9 -0
- package/bundled-skills/goal-instruction-writer/references/drift-control.md +160 -0
- package/bundled-skills/goal-instruction-writer/references/examples.md +220 -0
- package/bundled-skills/goal-instruction-writer/references/goal-contract.md +169 -0
- package/bundled-skills/goal-instruction-writer/references/loop-preview.md +113 -0
- package/bundled-skills/keenable-search-mcp/SKILL.md +176 -0
- package/bundled-skills/krexa/SKILL.md +221 -0
- package/bundled-skills/krexa/references/limits.md +42 -0
- package/bundled-skills/krexa/references/setup.md +60 -0
- package/bundled-skills/krexa/references/tools.md +59 -0
- package/bundled-skills/llm-cost-optimization/SKILL.md +1 -1
- package/bundled-skills/llmops-platform-engineering/SKILL.md +1 -1
- package/bundled-skills/multi-tenant-llm-hosting/SKILL.md +1 -1
- package/bundled-skills/music-generation-studio/SKILL.md +109 -90
- package/bundled-skills/outreachgenie-list-audit/LICENSE +21 -0
- package/bundled-skills/outreachgenie-list-audit/SKILL.md +60 -0
- package/bundled-skills/outreachgenie-list-audit/assets/fictional-snapshot.json +256 -0
- package/bundled-skills/outreachgenie-list-audit/references/capture.md +53 -0
- package/bundled-skills/outreachgenie-list-audit/references/checks.md +35 -0
- package/bundled-skills/outreachgenie-list-audit/references/setup.md +25 -0
- package/bundled-skills/outreachgenie-list-audit/scripts/audit.py +766 -0
- package/bundled-skills/outreachgenie-list-audit/scripts/test_audit.py +360 -0
- package/bundled-skills/pangolinfo-amazon-data-research/SKILL.md +170 -0
- package/bundled-skills/poster-design-studio/SKILL.md +109 -90
- package/bundled-skills/ppl-personal-crm/SKILL.md +118 -0
- package/bundled-skills/product-photo-studio/SKILL.md +109 -90
- package/bundled-skills/project-memory-log/LICENSE +21 -0
- package/bundled-skills/project-memory-log/SKILL.md +110 -0
- package/bundled-skills/project-memory-log/references/example-document-catalog.md +22 -0
- package/bundled-skills/project-memory-log/references/example-notes.md +16 -0
- package/bundled-skills/project-memory-log/references/example-operation-log.md +46 -0
- package/bundled-skills/project-memory-log/references/record-formats.md +77 -0
- package/bundled-skills/solidping/SKILL.md +87 -0
- package/bundled-skills/story-bible-continuity/SKILL.md +149 -0
- package/bundled-skills/story-bible-continuity/references/sbc-checker.md +367 -0
- package/bundled-skills/story-bible-continuity/references/story-bible-schema.md +91 -0
- package/bundled-skills/suno-lyrics-to-song/SKILL.md +109 -90
- package/bundled-skills/taasky/SKILL.md +376 -0
- package/bundled-skills/talking-avatar-video/SKILL.md +109 -90
- package/bundled-skills/uiverify-triage-visual-changes/SKILL.md +304 -0
- package/bundled-skills/unpaid-intern/SKILL.md +159 -0
- package/bundled-skills/viral-video-teardown-remake/SKILL.md +109 -90
- package/bundled-skills/voice-cloning-studio/SKILL.md +109 -90
- package/bundled-skills/voiceover-narration-studio/SKILL.md +109 -90
- package/package.json +1 -1
- package/skills_index.json +654 -24
|
@@ -11,7 +11,7 @@ author: beatra-ai
|
|
|
11
11
|
tags: [talking-avatar, talking-head, text-to-video, mcp, paid-api, beatra]
|
|
12
12
|
tools: [claude, codex, cursor, gemini]
|
|
13
13
|
license: "MIT-0"
|
|
14
|
-
license_source: "https://github.com/beatra-ai/talking-avatar-video-skill/blob/
|
|
14
|
+
license_source: "https://github.com/beatra-ai/talking-avatar-video-skill/blob/03e427c1220ef7efcfee083b37f4f31aa98311ab/LICENSE"
|
|
15
15
|
---
|
|
16
16
|
|
|
17
17
|
# Talking Avatar Video Skill
|
|
@@ -24,21 +24,20 @@ Turn one portrait and a short script into a talking avatar video, from inside Cl
|
|
|
24
24
|
This catalog entry is a **reviewed pointer, not the executable package**. It
|
|
25
25
|
contains no client code and performs no Beatra operation by itself. The package
|
|
26
26
|
it points to bundles three standard-library Python scripts that make network
|
|
27
|
-
calls
|
|
27
|
+
calls and store a credential. It has no self-updater: it never downloads
|
|
28
|
+
code and never changes its own files. Read
|
|
28
29
|
[Install](#install-pinned-verified-approved-twice) and
|
|
29
30
|
[Security & Safety Notes](#security--safety-notes) before activating it.
|
|
30
31
|
|
|
31
32
|
| Pinned identity | Value |
|
|
32
33
|
| --- | --- |
|
|
33
|
-
| Package | `talking-avatar-video` `0.
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
| Source tree | [`beatra-ai/talking-avatar-video-skill@251c968`](https://github.com/beatra-ai/talking-avatar-video-skill/tree/251c968deebb1c8f1dbfd0a8404e8e1be1528ac6/skills/talking-avatar-video) (full SHA `251c968deebb1c8f1dbfd0a8404e8e1be1528ac6`) |
|
|
34
|
+
| Package | `talking-avatar-video` `0.3.0` |
|
|
35
|
+
| Source commit | [`beatra-ai/talking-avatar-video-skill@03e427c`](https://github.com/beatra-ai/talking-avatar-video-skill/tree/03e427c1220ef7efcfee083b37f4f31aa98311ab/skills/talking-avatar-video) (full SHA `03e427c1220ef7efcfee083b37f4f31aa98311ab`) |
|
|
36
|
+
| Package tree | `e44d57ecf111824bd4081ff26c9f6e7b4b3bd0d2` (Git tree ID of `skills/talking-avatar-video` at that commit) |
|
|
37
37
|
| License | MIT No Attribution (MIT-0) |
|
|
38
38
|
|
|
39
|
-
The
|
|
40
|
-
binaries). Confirm that with the inspect commands below.
|
|
41
|
-
byte-identical to the source tree at the pinned commit.
|
|
39
|
+
The pinned tree holds regular files only (no symlinks, no executable bits, no
|
|
40
|
+
binaries). Confirm that with the inspect commands below.
|
|
42
41
|
|
|
43
42
|
## When to Use This Skill
|
|
44
43
|
|
|
@@ -48,72 +47,55 @@ byte-identical to the source tree at the pinned commit.
|
|
|
48
47
|
|
|
49
48
|
## Install (pinned, verified, approved twice)
|
|
50
49
|
|
|
51
|
-
### Step 1:
|
|
50
|
+
### Step 1: Fetch the pinned tree into a review directory
|
|
52
51
|
|
|
53
|
-
Explain that this
|
|
52
|
+
Explain that this fetches an external package from `github.com`, then ask
|
|
54
53
|
for approval. Only after approval:
|
|
55
54
|
|
|
56
55
|
```bash
|
|
57
56
|
umask 077
|
|
58
57
|
review_dir="$(mktemp -d)"
|
|
59
58
|
cd "$review_dir" || exit 1
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
'talking-avatar-video-skill-0.2.1.zip' | shasum -a 256 -c -
|
|
59
|
+
git clone --quiet --filter=blob:none --no-checkout https://github.com/beatra-ai/talking-avatar-video-skill.git src
|
|
60
|
+
git -C src checkout --quiet 03e427c1220ef7efcfee083b37f4f31aa98311ab -- skills/talking-avatar-video
|
|
61
|
+
test "$(git -C src rev-parse '03e427c1220ef7efcfee083b37f4f31aa98311ab:skills/talking-avatar-video')" = 'e44d57ecf111824bd4081ff26c9f6e7b4b3bd0d2' && echo TREE-OK
|
|
64
62
|
```
|
|
65
63
|
|
|
66
|
-
Stop if the
|
|
67
|
-
catalog entry, not from
|
|
64
|
+
Stop if the last command does not print `TREE-OK`. The expected commit and
|
|
65
|
+
tree IDs come from this catalog entry, not from the package or its website,
|
|
66
|
+
and Git addresses every fetched object by its hash.
|
|
68
67
|
|
|
69
68
|
### Step 2: Inspect before activation
|
|
70
69
|
|
|
71
70
|
```bash
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
find talking-avatar-video -type l -print # expect no output
|
|
75
|
-
find talking-avatar-video -type f -perm -111 -print # expect no output
|
|
76
|
-
grep -n '"auto_update": True' talking-avatar-video/scripts/mcp_client.py
|
|
71
|
+
git -C src ls-tree -r 03e427c1220ef7efcfee083b37f4f31aa98311ab -- skills/talking-avatar-video | awk '$1 != "100644"' # expect no output
|
|
72
|
+
grep -n -E 'maybe_auto_update|download_update|_apply_update' src/skills/talking-avatar-video/scripts/mcp_client.py # expect no output
|
|
77
73
|
```
|
|
78
74
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
git clone --quiet --filter=blob:none --no-checkout https://github.com/beatra-ai/talking-avatar-video-skill.git src
|
|
84
|
-
git -C src checkout --quiet 251c968deebb1c8f1dbfd0a8404e8e1be1528ac6 -- skills/talking-avatar-video
|
|
85
|
-
(cd talking-avatar-video && find . -type f | LC_ALL=C sort | xargs shasum -a 256) > archive.sha
|
|
86
|
-
(cd src/skills/talking-avatar-video && find . -type f | LC_ALL=C sort | xargs shasum -a 256) > tree.sha
|
|
87
|
-
cmp archive.sha tree.sha && echo IDENTICAL
|
|
88
|
-
```
|
|
75
|
+
The first check lists any symlink, executable, or submodule entry; the second
|
|
76
|
+
finds the entry points of the self-updater that earlier versions shipped.
|
|
89
77
|
|
|
90
|
-
Report to the user what the review found: `SKILL.md`, `manifest.json`,
|
|
91
|
-
|
|
78
|
+
Report to the user what the review found: `SKILL.md`, `manifest.json`,
|
|
79
|
+
`install-source.json` (the one-line marker `{"schema_version":1,"source":"github"}`),
|
|
80
|
+
the bundled Markdown references, and `scripts/authorize.py`,
|
|
92
81
|
`scripts/mcp_client.py`, `scripts/uninstall.py` (Python 3.10+, standard
|
|
93
82
|
library only, no dependency installation, no lifecycle hooks). Summarize the
|
|
94
|
-
network, credential, local-state, telemetry, and
|
|
95
|
-
under [Security & Safety Notes](#security--safety-notes).
|
|
83
|
+
network, credential, local-state, telemetry, and version-notice behavior
|
|
84
|
+
listed under [Security & Safety Notes](#security--safety-notes).
|
|
96
85
|
|
|
97
|
-
### Step 3: Copy in
|
|
86
|
+
### Step 3: Copy in
|
|
98
87
|
|
|
99
88
|
Ask for a **second, separate** approval, because this changes agent
|
|
100
89
|
configuration. Then copy the reviewed tree to the host's skills directory
|
|
101
|
-
(Claude Code shown; use the equivalent path for other hosts)
|
|
102
|
-
turn off silent self-update for that exact path:
|
|
90
|
+
(Claude Code shown; use the equivalent path for other hosts):
|
|
103
91
|
|
|
104
92
|
```bash
|
|
105
93
|
dest="$HOME/.claude/skills/talking-avatar-video"
|
|
106
|
-
test ! -e "$dest" || { echo "destination exists; stop and ask the user"; exit 1; }
|
|
107
|
-
cp -R talking-avatar-video "$dest"
|
|
108
|
-
python3 "$dest/scripts/mcp_client.py" update --auto off
|
|
94
|
+
test ! -e "$dest" && test ! -L "$dest" || { echo "destination exists; stop and ask the user"; exit 1; }
|
|
95
|
+
cp -R "src/skills/talking-avatar-video" "$dest"
|
|
109
96
|
```
|
|
110
97
|
|
|
111
|
-
|
|
112
|
-
`Automatic Beatra package updates are disabled.` It writes only
|
|
113
|
-
`~/.beatra/updates/<id>/state.json` and makes no network request. Run it
|
|
114
|
-
before `authorize.py`, `verify`, `tools`, `upload`, or `call`: in this
|
|
115
|
-
pinned version self-update is **on by default**. The setting is keyed to the
|
|
116
|
-
resolved install path, so repeat it after moving or re-copying the directory.
|
|
98
|
+
There is no update switch to turn off in this version.
|
|
117
99
|
|
|
118
100
|
### Step 4: Authorize as its own decision
|
|
119
101
|
|
|
@@ -156,16 +138,17 @@ arguments; never submit a replacement while the task is running.
|
|
|
156
138
|
|
|
157
139
|
## Update
|
|
158
140
|
|
|
159
|
-
This
|
|
160
|
-
|
|
161
|
-
|
|
141
|
+
This pinned version cannot update itself: it has no code that downloads or
|
|
142
|
+
replaces package files. `update` only reports what the store or tool that
|
|
143
|
+
installed the copy offers; for a copy installed by the steps above it finds
|
|
144
|
+
no such record and says to update the way you installed it. See the version
|
|
145
|
+
notice under [Security & Safety Notes](#security--safety-notes).
|
|
162
146
|
|
|
163
|
-
To move to a newer version, repeat Steps 1 to 3 for that
|
|
164
|
-
review directory,
|
|
165
|
-
(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
from `beatra.ai` without changing files.
|
|
147
|
+
To move to a newer version, repeat Steps 1 to 3 for that commit in a new
|
|
148
|
+
review directory, show the user the file-level changes against the installed
|
|
149
|
+
copy (for example `git -C src diff --stat 03e427c <new-commit> -- skills/talking-avatar-video`),
|
|
150
|
+
and replace the directory only after approval. A version not listed in this
|
|
151
|
+
entry has not been reviewed here.
|
|
169
152
|
|
|
170
153
|
## Uninstall
|
|
171
154
|
|
|
@@ -177,21 +160,25 @@ python3 "$dest/scripts/uninstall.py"
|
|
|
177
160
|
|
|
178
161
|
Read the JSON decision. `disconnected` means this was the last Beatra skill on
|
|
179
162
|
the device: the token was revoked (when `revoked` is `true`) and the files
|
|
180
|
-
`credentials.json`, `installation.json`, `host.json`, `skills.json`,
|
|
181
|
-
`
|
|
182
|
-
|
|
183
|
-
|
|
163
|
+
`credentials.json`, `installation.json`, `host.json`, `skills.json`,
|
|
164
|
+
`network.json`, `balance-holds.json`, `pending_authorization.json`, and
|
|
165
|
+
`.authorize.lock` under `~/.beatra` were removed. `keep_connection` means
|
|
166
|
+
another Beatra skill still uses the shared token, which stays.
|
|
167
|
+
`revoke_retry` means the server refused the revocation and nothing changed;
|
|
168
|
+
run it again shortly. The script never deletes the package directory: after
|
|
169
|
+
confirming the path it prints with the user, delete `$dest`.
|
|
184
170
|
|
|
185
171
|
`uninstall.py` does not remove `~/.beatra/updates/`. When the decision is
|
|
186
172
|
`disconnected` and no other Beatra skill is installed, remove that directory
|
|
187
|
-
|
|
188
|
-
days idle and can be revoked at once in the
|
|
173
|
+
and then the empty `~/.beatra`; otherwise leave them. A token that could not
|
|
174
|
+
be revoked expires after 15 days idle and can be revoked at once in the
|
|
175
|
+
Beatra Console under Agents.
|
|
189
176
|
|
|
190
177
|
## Best Practices
|
|
191
178
|
|
|
192
179
|
- ✅ Keep one approval per paid call, per upload set, and per install step.
|
|
193
180
|
- ✅ Report net charged credits from the terminal task, not the estimate.
|
|
194
|
-
- ❌ Do not
|
|
181
|
+
- ❌ Do not replace the installed copy with an unreviewed version silently.
|
|
195
182
|
- ❌ Do not print, paste, or move the token out of `~/.beatra/credentials.json`.
|
|
196
183
|
- ❌ Do not retry a paid call with a new request ID after an uncertain response.
|
|
197
184
|
|
|
@@ -202,27 +189,42 @@ days idle and can be revoked at once in the Beatra Console under Agents.
|
|
|
202
189
|
upstream model providers and can change; the service is provided as is.
|
|
203
190
|
- Outputs are probabilistic, not guaranteed unique or non-infringing, and need
|
|
204
191
|
human review before publication.
|
|
205
|
-
- This catalog entry reviews only the pinned
|
|
192
|
+
- This catalog entry reviews only the pinned tree above. A newer version is
|
|
206
193
|
a different review.
|
|
207
194
|
|
|
208
195
|
## Security & Safety Notes
|
|
209
196
|
|
|
210
197
|
`risk: critical` is deliberate.
|
|
211
198
|
|
|
212
|
-
- **Network.**
|
|
213
|
-
|
|
214
|
-
`
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
`
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
199
|
+
- **Network.** Every request is HTTPS and refuses redirects. Authorization
|
|
200
|
+
uses `api.beatra.ai` and tool calls go to `mcp.beatra.ai`; an upload is a
|
|
201
|
+
`PUT` of the approved file to the HTTPS address the server returns, without
|
|
202
|
+
the bearer token. Unless a cached decision is still valid (10 minutes to 7
|
|
203
|
+
days), each run first asks `https://api.beatra.ai/skill-route`, and also
|
|
204
|
+
`https://api.beatra.cn/skill-route` when the first is slow or answers `cn`,
|
|
205
|
+
which network to use. These probes carry no credential or package identity.
|
|
206
|
+
When the answer is `cn`, authorization and tool calls go to `api.beatra.cn`
|
|
207
|
+
and `mcp.beatra.cn` with the same bearer token, and the version notice
|
|
208
|
+
reads from `www.beatra.cn`; Beatra serves these `.cn` hosts from mainland
|
|
209
|
+
China.
|
|
210
|
+
`python3 "$dest/scripts/mcp_client.py" network --use ai` pins the `.ai`
|
|
211
|
+
hosts and stops the probes; a failed version-notice read can still retry
|
|
212
|
+
once on the other network.
|
|
213
|
+
- **Version notice, no self-update.** This version has no code that downloads
|
|
214
|
+
or replaces package files and writes nothing inside the install directory.
|
|
215
|
+
Before `verify`, `tools`, `upload`, or `call`, at most once every 24 hours
|
|
216
|
+
per install path, it records the check time and looks, read-only, for
|
|
217
|
+
records another installer left beside the package (ClawHub `origin.json`,
|
|
218
|
+
SkillHub or `skills` CLI lock entries, `gh skill` frontmatter). A copy
|
|
219
|
+
installed by the steps above normally has none and makes no request. When
|
|
220
|
+
one is found, it reads `https://beatra.ai/skills/talking-avatar-video/sources.json`
|
|
221
|
+
(no credential, 3-second timeout, 64 KiB cap) and, if that installer offers a
|
|
222
|
+
newer version, prints one line to stderr with the installer's own update
|
|
223
|
+
command. It never runs the command.
|
|
223
224
|
- **Uploads and third parties.** Prompts and uploaded media are sent to Beatra
|
|
224
225
|
and forwarded to the third-party model provider executing the task. Beatra
|
|
225
|
-
|
|
226
|
+
runs the service outside mainland China; on the `cn` route (see Network)
|
|
227
|
+
requests reach it through Beatra's hosts in mainland China. See the
|
|
226
228
|
[privacy policy](https://beatra.ai/en/privacy).
|
|
227
229
|
- **Likeness and reference media.** Uploaded portraits or reference clips are sent to Beatra and the model provider. Require approval for that exact file set.
|
|
228
230
|
- **Billing.** Paid tools consume prepaid credits. Credits for tasks that fail
|
|
@@ -230,20 +232,37 @@ days idle and can be revoked at once in the Beatra Console under Agents.
|
|
|
230
232
|
automatically; otherwise purchases are non-refundable, and actual usage can
|
|
231
233
|
exceed the estimate and leave a negative balance. See the
|
|
232
234
|
[terms](https://beatra.ai/en/terms).
|
|
233
|
-
- **Credentials.** `authorize.py` runs an OAuth device flow, opens the browser
|
|
234
|
-
and stores one bearer token in
|
|
235
|
-
`0700`, file `0600`). The token never
|
|
236
|
-
or output. It carries full Beatra
|
|
237
|
-
sliding 15-day idle lifetime, and is
|
|
238
|
-
device.
|
|
235
|
+
- **Credentials.** `authorize.py` runs an OAuth device flow, opens the browser
|
|
236
|
+
on the approval page, and stores one bearer token in
|
|
237
|
+
`~/.beatra/credentials.json` (directory `0700`, file `0600`). The token never
|
|
238
|
+
goes into argv, environment variables, or output. It carries full Beatra
|
|
239
|
+
scope, including `wallet:spend`, has a sliding 15-day idle lifetime, and is
|
|
240
|
+
shared by every Beatra skill on the device. While the user has not yet
|
|
241
|
+
selected Allow, the pending device code is kept in
|
|
242
|
+
`~/.beatra/pending_authorization.json` (`0600`) so a rerun finishes the same
|
|
243
|
+
approval instead of opening a new one. When `verify`, `tools`, `upload`, or
|
|
244
|
+
`call` finds no working token, the client makes one check of that saved
|
|
245
|
+
approval and stores the token if the user has already selected Allow; it
|
|
246
|
+
never starts a new authorization or opens a browser.
|
|
239
247
|
- **Local state.** `~/.beatra/` also holds `installation.json` (random
|
|
240
248
|
installation reference), `host.json` (agent platform and hostname),
|
|
241
|
-
`skills.json` (installed Beatra skill paths), `
|
|
242
|
-
|
|
243
|
-
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
249
|
+
`skills.json` (installed Beatra skill paths), `network.json` (route
|
|
250
|
+
decision, with a country code when the route answer includes one),
|
|
251
|
+
`balance-holds.json` (after an insufficient-credit refusal, that tool is
|
|
252
|
+
answered locally for up to 30 minutes; `call --recheck-balance` sends one
|
|
253
|
+
call), a short-lived `.authorize.lock`, and, per install path,
|
|
254
|
+
`updates/<id>/state.json` (last version check), `source.json` (install
|
|
255
|
+
source), and `registration.json` (last registration). Files are `0600`
|
|
256
|
+
except `host.json`, which follows the umask.
|
|
257
|
+
- **Telemetry.** Authorization sends the hostname as the device name, the
|
|
258
|
+
package slug and version, the detected agent platform (for example
|
|
259
|
+
`claude-code`, from environment variables), and the installation reference.
|
|
260
|
+
After connecting, at most once a day unless the version, platform, route, or
|
|
261
|
+
install source changes, the client makes a non-billable
|
|
262
|
+
`beatra.installations.register` call with those package and platform
|
|
263
|
+
fields, the release channel, the network route, the install source
|
|
264
|
+
(`github` for this tree), and coarse runtime facts: OS and OS version, CPU
|
|
265
|
+
architecture, Python version, locale, and UTC offset. Every tool call adds
|
|
247
266
|
`source_package_slug` and `source_platform`. There is no opt-out for these
|
|
248
267
|
fields.
|
|
249
268
|
- **Retention.** Account data is kept for the life of the account. Task
|
|
@@ -255,6 +274,6 @@ days idle and can be revoked at once in the Beatra Console under Agents.
|
|
|
255
274
|
|
|
256
275
|
## Additional Resources
|
|
257
276
|
|
|
258
|
-
- [Source tree at the pinned commit](https://github.com/beatra-ai/talking-avatar-video-skill/tree/
|
|
277
|
+
- [Source tree at the pinned commit](https://github.com/beatra-ai/talking-avatar-video-skill/tree/03e427c1220ef7efcfee083b37f4f31aa98311ab/skills/talking-avatar-video)
|
|
259
278
|
- [Product page](https://beatra.ai/skills/talking-avatar-video)
|
|
260
279
|
- [Terms](https://beatra.ai/en/terms) and [privacy policy](https://beatra.ai/en/privacy)
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: uiverify-triage-visual-changes
|
|
3
|
+
description: "Triage a UI Verify visual regression build from your coding agent over MCP: sort changed screenshots into regressions, intended changes and noise, then accept baselines."
|
|
4
|
+
category: testing
|
|
5
|
+
risk: critical
|
|
6
|
+
source: "https://github.com/uiverify/uiverify/tree/main/packages/skills/skills/triage-visual-changes"
|
|
7
|
+
source_repo: uiverify/uiverify
|
|
8
|
+
source_type: official
|
|
9
|
+
date_added: "2026-10-19"
|
|
10
|
+
author: igrlk
|
|
11
|
+
tags: [visual-testing, visual-regression, screenshot-testing, mcp, storybook, playwright, vitest]
|
|
12
|
+
tools: [claude-code, codex, cursor, gemini]
|
|
13
|
+
license: "MIT"
|
|
14
|
+
license_source: "https://github.com/uiverify/uiverify/blob/main/LICENSE"
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Triage a UI Verify build from your agent
|
|
18
|
+
|
|
19
|
+
When a build comes back **changed**, the dashboard shows a triptych per story (baseline / candidate /
|
|
20
|
+
diff). This skill does that review from your agent over the **UI Verify MCP** — read what changed, look
|
|
21
|
+
at the pixels when a number is ambiguous, then summarize or accept.
|
|
22
|
+
|
|
23
|
+
## When to Use This Skill
|
|
24
|
+
|
|
25
|
+
- Use when a UI Verify build reports changed or failed stories and the user wants the agent to review them instead of the dashboard.
|
|
26
|
+
- Use when the user asks to triage a build, summarize the visual regressions for a PR comment, or accept the new baselines.
|
|
27
|
+
- Use when the user wants the before-and-after of a pull request's UI changes, or to reply to or resolve a reviewer's comment on a diff.
|
|
28
|
+
- Requires a UI Verify project that uploads builds from CI, and the UI Verify MCP server connected in the agent.
|
|
29
|
+
|
|
30
|
+
## Connect the MCP (once)
|
|
31
|
+
|
|
32
|
+
The server is a remote Streamable-HTTP MCP at `https://uiverify.ai/mcp`. You log in once with your UI
|
|
33
|
+
Verify account in the browser (OAuth), and that one connection reaches every project in every team you
|
|
34
|
+
are a member of, so there is no per-project setup and no API key in the config. **Add it as a real MCP
|
|
35
|
+
server in your agent — don't hand-roll `curl` against the endpoint.** Over raw `curl` the image tools come
|
|
36
|
+
back as MCP image blocks a shell can't render, so the pixels are useless to a script; a native client shows
|
|
37
|
+
them to the model directly.
|
|
38
|
+
|
|
39
|
+
**Claude Code** — run in the project root:
|
|
40
|
+
```sh
|
|
41
|
+
claude mcp add --scope project --transport http uiverify https://uiverify.ai/mcp
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Then restart Claude Code, run `/mcp`, pick `uiverify`, and log in. `--scope project` writes the server to
|
|
45
|
+
the committed `.mcp.json`; it holds no secret, so the whole team gets it and each teammate logs in with
|
|
46
|
+
their own account.
|
|
47
|
+
|
|
48
|
+
**Cursor** — add to `.cursor/mcp.json` (commit it to share), then log in from Cursor's MCP settings:
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"mcpServers": {
|
|
52
|
+
"uiverify": { "url": "https://uiverify.ai/mcp" }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Any other MCP client (VS Code, Codex, Copilot, Gemini): point it at the same Streamable-HTTP URL and it
|
|
58
|
+
asks you to log in. Restart the agent session after adding the server so the tools load. If a client can
|
|
59
|
+
only reach it over HTTP by hand, prefer the `get_diff` tool (it returns downloadable image **URLs**) over
|
|
60
|
+
`render_diff_image` (inline pixels) — see the tool table below.
|
|
61
|
+
|
|
62
|
+
Tools it exposes:
|
|
63
|
+
|
|
64
|
+
| Tool | Does | Key args |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `list_projects` | Every project you can access, with its `projectId`, team, name, type, repo, and last build time. Only needed when you can access several projects: a `commitSha` / `prNumber` lookup and `list_builds` then take a `projectId` (with one project it is used automatically, and a call that's ambiguous returns an error listing them) | none |
|
|
67
|
+
| `list_builds` | Recent builds + gate status, to find the one to inspect | `projectId?`, `branch?`, `status?`, `limit?` |
|
|
68
|
+
| `get_build` | Lean triage of one build — the gate + `counts {total, changed, failed, unchanged}`, a build-wide `comments {total, unresolved}` review-comment tally, the AI tally, and the **first page (25)** of changed/failed stories (each with a `diffResultId`, diff %, and when AI review is on the judge's `aiVerdict`, `aiConfidence`, and for a regression `aiFlagReason` = its one-line "what looks unintended"), the page carrying a `nextCursor`. It does **not** dump the unchanged list — `counts.unchanged` is the signpost; page the rest with `list_build_stories`. `comments.unresolved > 0` means a human/agent left an open note — read it with `list_comments` before you accept | one of `commitSha` / `prNumber` / `buildId` |
|
|
69
|
+
| `list_build_stories` | Page through one build's stories by status — the only way to browse the full changed / failed / **unchanged** set beyond `get_build`'s first page. `counts.unchanged` from `get_build` is the exact count it pages. Every changed-story row (here and in `get_build`) carries its own `comments {total, unresolved}` | selector, `status: changed \| unchanged \| failed`, `cursor?`, `limit?` (default 25, max 100) |
|
|
70
|
+
| `get_diff` | Per-story diff metrics + **presigned image URLs** (baseline / candidate / diff) you can download to a file or link straight into a PR; when AI review is on, the judge's full call: `aiVerdict`, `aiConfidence`, `aiSummary` (what changed), `aiReasoning` (why), `aiFlagReason`; and a per-story `comments {total, unresolved}` (same signpost as `get_build`, scoped to the one story). Pass `storyId` to pull one story **even if it didn't change** — you get its current baseline URL, so you can show "identical to baseline" on a passed build | same selector, optional `storyId` |
|
|
71
|
+
| `render_diff_image` | The actual **pixels** of one image, inline for the vision model to look at (not a URL): `baseline` / `candidate` / `diff`, or `before_after` for a before-and-after crop zoomed to the changed region — one crop per region, stacked, when the story moved in several far-apart places (a header and a footer). When the story has an unresolved review comment, a text note saying so comes **before** the image | `diffResultId` (or `storyId` for a story that didn't change), `which` |
|
|
72
|
+
| `get_pr_changeset` | The **cumulative** "This PR vs base" changeset: what the *whole pull request* did to the UI vs the branch it merges into — `new` / `changed` / `removed` stories, each with review status (and the judge's verdict when AI review is on), plus `counts {new, changed, removed, unchanged}` and the **first page (25)** of each list. **Distinct from `get_build`**, which is one commit's gate: this survives in-PR accepts **and** merge, and catches an added-then-accepted story and a **removed** one that no single build's diff can see | one of `commitSha` / `prNumber` / `buildId` |
|
|
73
|
+
| `list_pr_stories` | Page one bucket of the PR-vs-base changeset beyond `get_pr_changeset`'s first page | selector, `kind: new \| changed \| removed`, `cursor?`, `limit?` |
|
|
74
|
+
| `review_diff` | Record a decision on one story. `accept` and `ignore` are **refused** while the story has an unresolved review comment; `deny` always works | `diffResultId`, `decision: accept \| deny \| ignore` |
|
|
75
|
+
| `accept_build` | Accept **every** changed story in a build at once. **Refused, accepting nothing,** while any changed story has an unresolved review comment — the error names those stories | same selector |
|
|
76
|
+
| `list_comments` | Read the review comments a designer/QA (or another agent) left on a build's diffs — every live comment across the build, each carrying its `diffResultId`, `authorType`, `body`, `side`, `parentId` (a reply's thread root), `anchor` (a point/region on the image), and `resolved`. This is the thing `get_build`/`get_diff`'s `comments` count points you to | one of `commitSha` / `prNumber` / `buildId` |
|
|
77
|
+
| `post_comment` | Leave a comment (or a threaded reply) on one story's diff — e.g. reply to a reviewer's question, or flag a regression back to them. Authored as the **agent**; a new root comment is refused if a newer build exists on the branch (comment on the latest), but replies are always allowed | selector + `diffResultId`, `body`, `side?`, `anchor?`, `parentId?` (reply to a root's id) |
|
|
78
|
+
| `resolve_comment` | Resolve (or reopen) a comment thread once its note is addressed | `commentId` (thread root), `resolved` |
|
|
79
|
+
| `update_comment` / `delete_comment` | Edit or remove a comment — the agent may only touch **agent-authored** comments | `commentId` (+ `body` for update) |
|
|
80
|
+
|
|
81
|
+
The comment tools (`list_comments` and the writes) are behind the team's image-comments feature; if they
|
|
82
|
+
are not exposed on your MCP connection, your team does not have it enabled, and `get_build`/`get_diff`
|
|
83
|
+
will simply report `comments {total: 0, unresolved: 0}`.
|
|
84
|
+
|
|
85
|
+
## Recipe 1 — "Triage this build"
|
|
86
|
+
|
|
87
|
+
Bucket the changes so the human sees signal, not 60 rows. Call `get_build` for the PR — it carries the
|
|
88
|
+
AI judge's call per story (`aiVerdict`, and for a regression the `aiFlagReason`) for the **first page** of
|
|
89
|
+
changes; if `counts.changed` is larger than that page, keep paging `list_build_stories { status:
|
|
90
|
+
"changed" }` on the `nextCursor` until it runs out, so no regression slips past the page boundary. **Read the judge before
|
|
91
|
+
you form your own view, and for anything that actually changed content, adjudicate it against the
|
|
92
|
+
before image, not in isolation:**
|
|
93
|
+
|
|
94
|
+
- **Render BOTH images, not just the diff.** `render_diff_image` `which: "baseline"` **and**
|
|
95
|
+
`which: "candidate"` and compare them. The green diff mask tells you *where* pixels moved, never
|
|
96
|
+
*whether the result is good* — a code block that went dark-on-dark, text that lost contrast, a
|
|
97
|
+
control that's now clipped all look like "some pixels changed" in the mask and only reveal
|
|
98
|
+
themselves as regressions in the before/after. Judging the candidate alone is how "it has colours
|
|
99
|
+
now → improvement" passes an illegible block. Pull `get_diff` for the judge's `aiReasoning` /
|
|
100
|
+
`aiFlagReason` on the ones it flagged.
|
|
101
|
+
|
|
102
|
+
- **Read the human's comments before you decide.** If `get_build`'s `comments.unresolved > 0` (or a
|
|
103
|
+
`get_diff` story shows `comments`), a designer/QA or another agent has left a note on this build —
|
|
104
|
+
`list_comments` reads them, each tied to its `diffResultId` so you can match a note to the story in your
|
|
105
|
+
buckets. A comment is context the pixels don't carry ("this spacing is intentional, don't revert it" /
|
|
106
|
+
"the logo is wrong here"), so read it before you bucket the story. You can't accept over one anyway:
|
|
107
|
+
`accept_build` and `review_diff` accept/ignore refuse a story with an **unresolved** comment. The loop is
|
|
108
|
+
read the note → do what it asks (often a code change and a new push) → `resolve_comment` → accept.
|
|
109
|
+
Never resolve a note just to unblock the accept; resolve it because you addressed it.
|
|
110
|
+
|
|
111
|
+
Report in four buckets, with real story names and % deltas:
|
|
112
|
+
|
|
113
|
+
1. **Regression — a real change that's wrong** — content changed and the after is broken or worse:
|
|
114
|
+
illegible/low-contrast text, clipping, overlap, missing content, a control that stopped reading as
|
|
115
|
+
itself. **A regression the current PR *caused* is still a regression** — "my diff explains it"
|
|
116
|
+
says nothing about whether it's correct. Never accept these; they're the reason to triage.
|
|
117
|
+
2. **Intended change** — content changed and the after is correct and matches the PR's stated intent
|
|
118
|
+
(a deliberate restyle, new copy, a genuinely new story). These still want a human eye, but they're
|
|
119
|
+
accept candidates.
|
|
120
|
+
3. **Cosmetic reflow** — real diff pixels, but the diff image shows the *same* content shifted a few px
|
|
121
|
+
(a row moved down ~5px, text ghosted lower). Not a content change.
|
|
122
|
+
4. **Rendering noise — safe to accept** — sub-0.4% jitter on chart edges / anti-aliased lines. Pure
|
|
123
|
+
render jitter.
|
|
124
|
+
|
|
125
|
+
**The judge's `regression` verdict is a reason to look harder, never to dismiss.** If you're about to
|
|
126
|
+
call a story the judge flagged "intended anyway", you need a concrete reason from the before/after that
|
|
127
|
+
refutes its `aiFlagReason` — not "it's a colour change, probably fine." When you can't refute it, trust
|
|
128
|
+
it.
|
|
129
|
+
|
|
130
|
+
Example output shape:
|
|
131
|
+
> **67 changed stories → buckets.**
|
|
132
|
+
> **⚠️ Regressions (2)** — real changes that look wrong, do NOT accept: `SetupWizard/Playwright` (8.3%,
|
|
133
|
+
> code block now dark-on-dark / illegible — judge flagged `regression`), `Card/Compact` (5.1%, title
|
|
134
|
+
> clipped) …
|
|
135
|
+
> **1. Intended changes (11)** — content changed, looks correct, accept candidates: `Hero/Default` (14%,
|
|
136
|
+
> new headline copy), …
|
|
137
|
+
> **2. Cosmetic reflow (9)** — real pixels, vertical shift only: `EventStatusCard/All Variants` (4.1%,
|
|
138
|
+
> rows shifted ~5px), `TestingInit/Playground` (3.7%), …
|
|
139
|
+
> **3. Chart anti-aliasing noise (6)** — sub-0.4% edge jitter, safe to accept: `FunnelChart/Smaller
|
|
140
|
+
> Screen` (3.2%), `UpliftChart` (single 1px mark), …
|
|
141
|
+
> **New stories (12)** — first baseline, nothing to compare: `Button/AllVariants`, …
|
|
142
|
+
|
|
143
|
+
Never accept from inside the triage step — surface the buckets and let the human decide, or do it
|
|
144
|
+
explicitly in recipe 3.
|
|
145
|
+
|
|
146
|
+
## Recipe 2 — "Summarize the visual regressions"
|
|
147
|
+
|
|
148
|
+
Same read, but output the changes that need a human — the ⚠️ regressions first, then the intended
|
|
149
|
+
content changes — in a PR-comment shape, one line each, no reflow/noise. This is the comment to drop on
|
|
150
|
+
the PR:
|
|
151
|
+
|
|
152
|
+
> 🔎 **Visual review — 1 regression, 2 intended** (of 67 flagged; 64 reflow/noise, listed below the fold)
|
|
153
|
+
> - ⚠️ `SetupWizard/Playwright` — code block dark-on-dark, illegible (8.3%, judge: regression)
|
|
154
|
+
> - `Pricing/Card` — CTA button color changed blue→green (12.4%)
|
|
155
|
+
> - `Nav/Header` — logo 8px larger (3.1%)
|
|
156
|
+
|
|
157
|
+
## Recipe 3 — "Accept all the new baselines"
|
|
158
|
+
|
|
159
|
+
When the changes are all intended (a deliberate restyle) or all noise **and you've confirmed no
|
|
160
|
+
regression is hiding in the list** (bucket ⚠️ empty), advance every changed story's baseline in one call:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
accept_build { prNumber: 123 }
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Don't let "the headline change is intended" halo onto the whole build — a global CSS or theme change
|
|
167
|
+
sweeps into stories the PR never meant to touch, and "the PR caused it" is not "the PR intended it."
|
|
168
|
+
Each changed story earns its bucket on its own before-and-after.
|
|
169
|
+
|
|
170
|
+
For a targeted accept (some real, some not), loop `review_diff` per `diffResultId` with
|
|
171
|
+
`accept` / `ignore` / `deny` instead — accept the intended ones, ignore the noise, leave real
|
|
172
|
+
regressions for a human.
|
|
173
|
+
|
|
174
|
+
## Recipe 4 — "Put the before/after in the PR"
|
|
175
|
+
|
|
176
|
+
Keep the human in the PR instead of sending them to the dashboard. After you've triaged, post the
|
|
177
|
+
changed stories inline:
|
|
178
|
+
|
|
179
|
+
- **The fastest single image:** `render_diff_image` `which: "before_after"` gives you one PNG, before and
|
|
180
|
+
after side by side, cropped to the changed region (one crop per region, stacked, if the story moved in
|
|
181
|
+
several far-apart places) — the least to eyeball. Save it and attach it.
|
|
182
|
+
- **Downloadable files / durable links:** `get_diff` returns presigned `baselineUrl` / `candidateUrl` /
|
|
183
|
+
`diffUrl`. Download them (`curl -L "$url" -o before.png`) to attach to the PR, or drop the build link
|
|
184
|
+
and the URLs into a comment. Always include the build link (`https://uiverify.ai/builds/<id>`) so the
|
|
185
|
+
reviewer can open the full triptych.
|
|
186
|
+
|
|
187
|
+
A good PR comment: the one-line-per-regression summary from Recipe 2, the before/after image for the
|
|
188
|
+
regressions, and the build link. Post it, don't make them go looking.
|
|
189
|
+
|
|
190
|
+
## Recipe 5 — "What did this whole PR do to the UI?"
|
|
191
|
+
|
|
192
|
+
`get_build` answers one commit — *is anything unreviewed on this build*. It does **not** prove the
|
|
193
|
+
**whole PR** did what you intended, and it's blind to two things by construction: a story you **added and
|
|
194
|
+
accepted earlier in the PR** (the latest build renders it clean, so it never shows as changed) and a
|
|
195
|
+
**removed** story (a deleted or renamed baseline — no build renders it, so no per-build diff flags it).
|
|
196
|
+
`get_pr_changeset` is the only surface that catches both, so run it before you call a PR done.
|
|
197
|
+
|
|
198
|
+
Pull it for the PR and read the whole head-vs-base picture:
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
get_pr_changeset { prNumber: 123 } → new / changed / removed vs the base branch
|
|
202
|
+
list_pr_stories { prNumber: 123, kind: "removed" } → page any one bucket
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Hold every entry to one bar: **can you attribute it to something this PR's diff actually did?**
|
|
206
|
+
|
|
207
|
+
- **Yes, and it's correct** → the intended visual impact of the PR.
|
|
208
|
+
- **A change you can't attribute to your own diff** → stop. Don't accept it, don't dismiss it as flake,
|
|
209
|
+
don't "re-run and see." Say so and flag it for a human — the likely cause is a baseline that moved when
|
|
210
|
+
it shouldn't have, which is silent by construction.
|
|
211
|
+
- **A `removed` story you didn't intend** → an accidental deletion (or an unintended rename, which reads
|
|
212
|
+
as a remove plus an add). Flag it loudly; don't let a green check ship it.
|
|
213
|
+
|
|
214
|
+
The changeset is GA — no flag to enable, and on a **public** project anyone can read it for a build
|
|
215
|
+
without logging in.
|
|
216
|
+
|
|
217
|
+
## Recipe 6 — "Answer or resolve a review comment"
|
|
218
|
+
|
|
219
|
+
When a reviewer's note is a question you can answer, or points at something you just fixed, close the loop
|
|
220
|
+
from the agent instead of making them chase you. Read the thread with `list_comments`, then:
|
|
221
|
+
|
|
222
|
+
- **Reply in the thread** — `post_comment { diffResultId, body, parentId }` where `parentId` is the root
|
|
223
|
+
comment's `id` (a reply inherits the root's side and needs no anchor of its own). Use it to answer
|
|
224
|
+
"why did this move?" with the diff you made, or to confirm "fixed in the next push."
|
|
225
|
+
- **Flag a regression back** — `post_comment { diffResultId, body, anchor? }` as a new root, to point the
|
|
226
|
+
reviewer at a story you're leaving for them (pair it with the ⚠️ bucket from Recipe 1).
|
|
227
|
+
- **Resolve** — `resolve_comment { commentId, resolved: true }` once the note is addressed (you made the
|
|
228
|
+
change it asked for, or answered the question). Resolve **before** you accept: an open thread makes
|
|
229
|
+
`accept_build` / `review_diff` refuse that story. Only reach for this when the thread is genuinely done;
|
|
230
|
+
the open comment is the signal that stops a premature accept.
|
|
231
|
+
|
|
232
|
+
Your key authors comments as the **agent**, and can only edit/delete comments it authored — never touch a
|
|
233
|
+
human's comment.
|
|
234
|
+
|
|
235
|
+
## Passed build? You can still show the pixels
|
|
236
|
+
|
|
237
|
+
A build with no changes shows no triptych — but the components still rendered, and "nothing changed" is
|
|
238
|
+
only trustworthy if you can see it. **Enumerate the unchanged set** with `list_build_stories { status:
|
|
239
|
+
"unchanged" }` (page it on the returned `nextCursor`), then pull any story's current image by id:
|
|
240
|
+
`get_diff { buildId, storyId }` for its baseline URL, or `render_diff_image { storyId, which: "baseline" }`
|
|
241
|
+
for the pixels. Use it to
|
|
242
|
+
confirm a component looks right on a green build, or to hand the reviewer "here it is, identical to
|
|
243
|
+
baseline" without opening the dashboard.
|
|
244
|
+
|
|
245
|
+
## Guardrails
|
|
246
|
+
|
|
247
|
+
- **Read before you write.** Always `get_build` (and `render_diff_image` for anything ambiguous) before
|
|
248
|
+
`review_diff` / `accept_build`. Don't accept a build you haven't looked at.
|
|
249
|
+
- **Compare before-and-after, never the after alone.** For any story that changed content, render
|
|
250
|
+
`which: "baseline"` AND `which: "candidate"` and look at both — the diff mask shows where, the pair
|
|
251
|
+
shows whether it got worse (contrast/legibility, clipping, layout). "It has colours / it moved" is not
|
|
252
|
+
"it's better."
|
|
253
|
+
- **The AI judge's `regression` is a signal to trust by default.** Overriding it needs a concrete reason
|
|
254
|
+
from the before/after that refutes its `aiFlagReason`, not a hand-wave. Attributable-to-this-PR is not
|
|
255
|
+
a reason to dismiss it.
|
|
256
|
+
- **Bulk-accept is a baseline change.** `accept_build` makes the candidate the new truth for every
|
|
257
|
+
changed story — only reach for it when you've confirmed there's no real regression hiding in the list.
|
|
258
|
+
- **An unresolved comment blocks the accept.** `get_build`'s `comments.unresolved > 0` means a human left
|
|
259
|
+
a note you haven't read — `list_comments` it and honor it before `review_diff` / `accept_build`. A
|
|
260
|
+
reviewer commenting "don't accept this" that an agent bulk-accepts anyway is exactly the failure this
|
|
261
|
+
count exists to prevent.
|
|
262
|
+
- **Distinguish "new story" from "changed story."** A first-baseline story has nothing to diff; it's not
|
|
263
|
+
a regression, just needs a baseline. Bucket it separately.
|
|
264
|
+
|
|
265
|
+
## Examples
|
|
266
|
+
|
|
267
|
+
### Example 1: Triage the build for a pull request
|
|
268
|
+
|
|
269
|
+
The user says: "Triage the UI Verify build for PR 123."
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
get_build { prNumber: 123 }
|
|
273
|
+
render_diff_image { diffResultId: "<diffResultId from get_build>", which: "before_after" }
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Bucket each changed story as a regression, cosmetic reflow or rendering noise from its before-and-after, then report the regressions by story name.
|
|
277
|
+
|
|
278
|
+
### Example 2: Accept the intended changes
|
|
279
|
+
|
|
280
|
+
The user says: "Those all come from the new button style, accept them."
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
accept_build { prNumber: 123 }
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Only after every changed story was looked at and none is a regression. For a mixed build, call `review_diff { diffResultId: "<id>", decision: "accept" }` for each intended story instead.
|
|
287
|
+
|
|
288
|
+
## Limitations
|
|
289
|
+
|
|
290
|
+
- Needs a UI Verify account and a project whose CI uploads builds with the `uiverify` CLI (Storybook, Playwright or Vitest); with no build there is nothing to triage.
|
|
291
|
+
- Needs network access to the hosted MCP server at `https://uiverify.ai/mcp` and a one-time browser login, which the agent cannot complete on its own.
|
|
292
|
+
- AI verdict fields appear only when AI review is on for the project, and the comment tools only when the team has image comments enabled.
|
|
293
|
+
- Over raw HTTP the image tools return MCP image blocks a shell cannot show; use a native MCP client, or `get_diff` for image URLs.
|
|
294
|
+
|
|
295
|
+
## Security & Safety Notes
|
|
296
|
+
|
|
297
|
+
- `review_diff` (accept) and `accept_build` change the project's baselines on the service, and later builds are compared against them. Look at the before and after first, and never bulk-accept a build that may hide a regression.
|
|
298
|
+
- The server refuses accept and ignore while a story has an unresolved review comment; read it with `list_comments` and honour it.
|
|
299
|
+
- `get_diff` returns presigned image URLs that work for anyone holding them until they expire. Share them only where the team would share the screenshot.
|
|
300
|
+
- Each person connects with their own OAuth login; there is no API key in `.mcp.json`.
|
|
301
|
+
|
|
302
|
+
## Catalog adaptation
|
|
303
|
+
|
|
304
|
+
Copied from the official MIT source above at commit `181d9e4` with its instructions unchanged; this catalog adds When to Use This Skill, Examples, Limitations and Security & Safety Notes.
|