Install
$ agentstack add skill-dundas-thinkrun-ux-audit ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
UX Audit Skill
You are a world-class UX designer and QA engineer. Your job is to walk through a user journey on a product using a browser session, take screenshots at every meaningful step, and produce a structured UX report with a complete fix list.
Mode Selection
Local mode — use when the product requires auth/cookies (your real logged-in session):
- Controls your actual Chrome via the ThinkRun extension + native host
- All commands operate on the tab you attach to
- Best for: apps behind login, staging environments with your cookies
Cloud mode — use for public-facing URLs, headless scraping, no auth needed:
- Provisions an isolated cloud browser
- Driven with
thinkrun cloud start+--mode cloud(see the web-browse skill) - Best for: marketing pages, public flows, pre-auth journeys
Step 0 — Configure the Audit
PRODUCT=""
PRODUCT_URL=""
AUDIT_DATE=$(date +%Y-%m-%d)
JOURNEY=""
If testing against localhost, check what's actually on the port before assuming the right app is there — other services may be squatting the default port:
PORT=$(printf '%s\n' "$PRODUCT_URL" | sed -nE 's#.*:([0-9]+).*#\1#p')
[ -n "$PORT" ] && lsof -iTCP:"$PORT" -sTCP:LISTEN 2>/dev/null | head -3
Step 1 — Start Session
Local Mode (auth required)
# List available Chrome tabs
thinkrun tabs
# Attach to an existing tab (use a clean one — New Tab, or any non-critical tab)
# TAB_ID comes from the tabs output above
TAB_ID=656847550
thinkrun attach $TAB_ID
# Navigate to the product
thinkrun navigate "$PRODUCT_URL"
sleep 2
The attached tab is now the active session. All subsequent commands route to it automatically — no session ID needed.
Cloud Mode (no auth required)
# Start an isolated cloud browser; it becomes the active session.
thinkrun cloud start
# Subsequent commands run against it. Force cloud per-command with --mode cloud.
thinkrun navigate "$PRODUCT_URL" --mode cloud
# When done: thinkrun cloud stop
Step 2 — Helper Functions (Local Mode)
# Navigate and wait for page load
nav() {
thinkrun navigate "$1"
sleep 2
}
# Screenshot — saves to /tmp, read the path with the Read tool
shot() {
local label="$1"
local result=$(thinkrun screenshot --output "/tmp/ux_${label}.png")
echo "Screenshot: /tmp/ux_${label}.png"
# Then use Read tool on that path to observe the image
}
# Click by CSS selector
click_sel() {
thinkrun click "$1"
sleep 1
}
# Click by visible button/link text (safe evaluate — avoids ambiguous selectors)
click_text() {
thinkrun evaluate "[...document.querySelectorAll('button,a,[role=button]')].find(el=>el.textContent.trim()==='$1')?.click()"
sleep 1
}
# Type into a React-controlled input (triggers onChange via keyboard events)
# Use `type` for React apps, `fill` for plain HTML inputs
type_react() {
local selector="$1"
local value="$2"
thinkrun click "$selector"
thinkrun type "$selector" "$value"
}
# Get current URL
current_url() {
thinkrun url
# Returns: {"data": "http://..."} — data is a plain string
}
# Scroll the page
scroll_down() {
thinkrun scroll --down "${1:-500}"
}
scroll_up() {
thinkrun scroll --up "${1:-500}"
}
# Extract visible text
read_text() {
thinkrun evaluate "([...document.querySelectorAll('h1,h2,h3,p,label,span')].map(e=>e.textContent.trim()).filter(t=>t.length>4).join('\n')).slice(0,2000)"
}
Step 3 — Walk the Journey
For each step:
- Perform the action (navigate, click, type, scroll)
- Wait for state to settle (
sleep 1orsleep 2) - Take a screenshot:
thinkrun screenshot --output "/tmp/ux_NN_label.png" - Read the screenshot file with the Read tool to observe it
- Note: what you see vs what you expected
Standard Journey Template
# 1. Landing / Homepage
thinkrun navigate "$PRODUCT_URL"
sleep 2
thinkrun screenshot --output "/tmp/ux_01_homepage.png"
# → Read tool: /tmp/ux_01_homepage.png
# Observe: CTA clarity, value proposition, onboarding path
# 2. Auth / Login (if required)
thinkrun navigate "${PRODUCT_URL}/login"
sleep 1
thinkrun screenshot --output "/tmp/ux_02_login.png"
# → Read tool: /tmp/ux_02_login.png
# Fill login form (use type for React-controlled inputs, fill for plain HTML)
thinkrun click "input[type=email]"
thinkrun type "input[type=email]" "test@example.com"
thinkrun click "input[type=password]"
thinkrun type "input[type=password]" "testpassword"
thinkrun click "button[type=submit]"
sleep 3
thinkrun screenshot --output "/tmp/ux_03_post_login.png"
# → Read tool: /tmp/ux_03_post_login.png
# Check: Did login succeed? What URL are we on?
thinkrun url
# 3. Core Action
thinkrun screenshot --output "/tmp/ux_04_core_action_start.png"
# ... perform the action ...
sleep 2
thinkrun screenshot --output "/tmp/ux_05_core_action_result.png"
# 4. Scroll to see full content
thinkrun scroll --down 600
thinkrun screenshot --output "/tmp/ux_06_scrolled.png"
# 5. Error Path (submit empty form, invalid input, etc.)
# navigate back, try invalid actions...
thinkrun screenshot --output "/tmp/ux_07_error_state.png"
# 6. Accessibility snapshot (reveals element structure, roles, text)
thinkrun snapshot
Step 4 — Observation Framework
At each screenshot, read the image and score against these dimensions:
| Dimension | Questions to Ask | |-----------|-----------------| | Clarity | Is it immediately obvious what to do next? | | Feedback | Does the UI communicate what's happening? | | Progress | Can the user tell how far along they are? | | Output | Is the result visible and readable? | | Error visibility | Are failures explained clearly, with a recovery path? | | Navigation | Easy to go back, forward, or to related sections? | | Performance feel | Does it feel fast or sluggish? Is there a loading indicator? | | Empty states | What does a new user see before any data exists? | | Mobile | Does the layout hold at 375px? |
Rate each: ✅ Good / 🟡 Needs work / 🔴 Broken
Step 5 — CLI DX Checklist (if product has a CLI)
PRODUCT_CLI="" # leave empty to skip
if [ -n "$PRODUCT_CLI" ]; then
$PRODUCT_CLI --help
$PRODUCT_CLI --version
fi
Step 6 — Report Format
## UX Audit: —
### Journey Tested
### Journey Map
| Step | Expected | Actual | Status |
|------|----------|--------|--------|
| 1. Homepage | Clear CTA | ... | ✅/🟡/🔴 |
### Critical Issues 🔴
- **Issue title**: Description. Screenshot: `ux_07_error_state.png`. Impact: ...
### Moderate Issues 🟡
- **Issue title**: Description. Screenshot: `ux_03_post_login.png`. Impact: ...
### What Works Well ✅
- Feature and why it works well.
### Scores by Dimension
| Dimension | Score | Notes |
|-----------|-------|-------|
| Clarity | ✅ | ... |
| Feedback | 🔴 | ... |
### Top 3 Fixes (Priority Order)
1. **Fix title** — rationale and expected impact
2. **Fix title** — rationale and expected impact
3. **Fix title** — rationale and expected impact
Deliver the report wherever your team tracks findings — a Markdown file in the repo, an issue per critical finding, or your task tracker. Keep the screenshot files referenced by the report so findings stay verifiable.
Known Gotchas
filldoesn't trigger ReactonChange— usetypeinstead for React-controlled inputs;fillworks for plain HTML inputs- Screenshot returns a local file path —
{"data": {"path": "/tmp/thinkrun-xxx.png"}}. Use the Read tool on that path to view it. There is no--labelflag. thinkrun urlreturns a plain string —{"data": "http://..."}not{"data": {"url": "..."}}. Parse asd['data'].- Scroll syntax —
thinkrun scroll --down 500(notscroll down 500) - Never use a generic
buttonselector when multiple buttons exist — usebutton[type=submit]orclick_texthelper evaluatecan timeout — keep scripts short. Avoiddocument.body.innerTexton large SPAs; use targeted selectors instead- CSRF-protected forms — auth forms need CSRF token. If the app fetches one after load, the fetch must complete before submit. Use
sleep 2after navigation before filling. - Tab becoming unresponsive — if commands timeout, use
thinkrun tabsto find a responsive tab, thenthinkrun attachto switch switch-tab≠attach—switch-tabchanges Chrome's active tab for visual focus;attachchanges which tab receives CLI commands. You need both when switching tabs.- Cloud mode screenshot —
thinkrun screenshot --output /tmp/sc.png --mode cloudsaves the file directly; read the path with the Read tool
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: dundas
- Source: dundas/thinkrun
- License: MIT
- Homepage: https://thinkrun.ai
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.