@gyeonghokim/uxlint
v4.5.0
Published
AI-powered UX review CLI for web apps — guided by your product personas and key features
Maintainers
Readme
uxlint
AI-powered UX review CLI for web apps — guided by your product personas and key features.
Demo
UI components while analysis

Reports using xAI provider, grok-4-1-fast-reasoning model

Overview
uxlint is a CLI tool that generates a UX evaluation report for a target web application using AI. It takes your configuration file as input — including the main and sub page URLs, freeform descriptions of key features on each page, and your customer personas — and outputs a persona-aware, task-oriented UX report to the path you specify.
Designed for frontend engineers who want quick, actionable UX feedback aligned with real user contexts.
Key capabilities
- Persona-aware analysis using your provided persona descriptions
- Page-by-page evaluation guided by your freeform feature descriptions
- Accessibility violations measured, not guessed, with the rule that caught each one
- Core Web Vitals measured per page, so a report can be compared with an earlier one
- Every finding labelled as measured or as AI judgement, so you know what you can dispute
- Actionable recommendations prioritized for frontend teams
- Single command execution with zero boilerplate beyond one config file
Installation
npm install -g @gyeonghokim/uxlintOr use directly with npx (no installation required):
npx @gyeonghokim/uxlintOn Linux
For using UXLint Cloud features, uxlint currently uses libsecret to store your OAuth credentials, so you may need to install it.
Depending on your distribution, you will need to run the following command:
# Debian/Ubuntu
sudo apt-get install libsecret-1-dev
# Red Hat-based
sudo yum install libsecret-devel
# Arch Linux
sudo pacman -S libsecretBrowser requirements
uxlint drives a real Chrome to analyse your pages. Chrome is not bundled and is not downloaded for you — it must already be installed.
- Chrome stable, current stable or newer — matching the browser tooling's own requirement. uxlint does not enforce a version number: whether a browser is usable is settled by launching it, and one too old to drive is reported with the browser's own explanation.
- Default locations searched:
/opt/google/chrome/chrome(Linux),/Applications/Google Chrome.app/Contents/MacOS/Google Chrome(macOS),C:\Program Files\Google\Chrome\Application\chrome.exe(Windows). - Installed elsewhere? Set
browser.executablePath.
uxlint checks for a usable browser before it starts analysing, so a missing or unusable one fails immediately with instructions rather than partway through a run.
On WSL
Point uxlint at a Linux-native Chrome with browser.executablePath (for example /usr/bin/google-chrome). uxlint searches Linux locations only, so it will not silently pick up a Windows Chrome through /mnt/c — a Windows browser driven from a Linux process is a known source of Target closed failures, and reaching it is not something you want to happen by accident.
In a container
Add Chrome to your image. A minimal Debian-based example:
FROM node:24-slim
RUN apt-get update && apt-get install -y --no-install-recommends wget gnupg ca-certificates \
&& wget -qO- https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/google-chrome.gpg \
&& echo "deb [arch=amd64 signed-by=/usr/share/keyrings/google-chrome.gpg] https://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \
&& apt-get update && apt-get install -y --no-install-recommends google-chrome-stable \
&& rm -rf /var/lib/apt/lists/*Most containers do not permit Chrome's security sandbox to start — this affects containers running as an ordinary user as well as ones running as root. uxlint detects this and disables the sandbox so the run can proceed, and says so in its output. Pages are then rendered without sandbox isolation. If that matters for the sites you analyse, run with a relaxed seccomp profile instead (for example --security-opt seccomp=unconfined), which lets the sandbox start normally and leaves it enabled.
What leaves your machine
By default, nothing derived from the URLs you analyse is sent anywhere except the target site itself. Specifically, uxlint disables:
- field-data lookups that would send analysed URLs to the Google CrUX API,
- usage statistics reporting by the browser tooling,
- the browser tooling's own update check against the npm registry.
Set browser.allowExternalData: true to opt in to the first two. When you do, the report records that the run was permitted to consult external data — uxlint does not observe the traffic, so it reports the permission rather than claiming the lookups happened.
Browser settings
browser:
executablePath: /opt/google/chrome/chrome # optional; default locations searched when absent
acceptInsecureCerts: true # default true — tolerate self-signed/expired certificates
allowExternalData: false # default false — send nothing derived from analysed URLs to third parties| Setting | Default | Meaning |
| --------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| executablePath | unset | Where Chrome lives, when it is not in a default location. When set, it is the only path searched. |
| acceptInsecureCerts | true | Tolerate untrusted TLS certificates. This is what every earlier release did unconditionally; it is now visible and switchable. Set false to have certificate problems fail the page. |
| allowExternalData | false | Permit external data lookups. Leave off when analysing staging hosts, internal tools, or URLs carrying preview tokens. |
An unrecognised key or a wrong type in this block stops the run before any page is analysed, naming the offending key.
Analysis settings
analysis:
pageTimeLimitMs: 600000 # optional; default 600000 — per-page wall-clock bound in milliseconds| Setting | Default | Meaning |
| ----------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| pageTimeLimitMs | 600000 | How long one page may take before uxlint gives up on it. An expired page is recorded partial with the expiry as its reason, and the run continues with the remaining pages. |
The default is calibrated to leave wide headroom over measured healthy page durations; a stuck provider or a wedged browser can no longer stall the whole pipeline until an external job timeout kills it. As with browser, an unrecognised key or wrong type here fails fast before any analysis.
Quick start
npx @gyeonghokim/uxlint --interactiveuxlint supports two execution modes: Interactive mode (with UI) and CI mode (headless). The behavior depends on the --interactive flag and whether a configuration file exists.
Scenario 1: Interactive mode without config (Wizard)
When you run uxlint --interactive without a configuration file, the interactive wizard launches:
uxlint --interactive
# or
npx @gyeonghokim/uxlint --interactiveThe wizard guides you through:
- Main page URL
- Additional pages (optional)
- Feature descriptions for each page
- User personas
- Report output path
- Option to save configuration to a file
After completing the wizard, analysis runs automatically and generates the report.
Scenario 2: Interactive mode with config (Direct analysis)
When you run uxlint --interactive with an existing .uxlintrc.yml or .uxlintrc.json file, the wizard is skipped and analysis starts immediately:
uxlint --interactive
# or
npx @gyeonghokim/uxlint --interactiveThe CLI reads the configuration file and runs analysis with a visual progress UI.
Scenario 3: CI mode with config (Headless)
When you run uxlint without the --interactive flag with a configuration file, it runs in CI mode (no UI):
uxlint
# or
npx @gyeonghokim/uxlintThis mode is designed for CI/CD pipelines, UI is disabled.
Scenario 4: CI mode without config (Error)
When you run uxlint without the --interactive flag without a configuration file, it exits with an error:
uxlint
# Error: Configuration file not found. Use --interactive flag to create one,
# or create .uxlintrc.yml or .uxlintrc.json in the current directory.Solution: Use uxlint --interactive to create a configuration file, or manually create .uxlintrc.yml or .uxlintrc.json in your project root.
Quick reference
| Command | Config file exists? | Behavior |
| ---------------------- | ------------------- | ----------------------------------- |
| uxlint --interactive | ❌ No | Launches wizard, then runs analysis |
| uxlint --interactive | ✅ Yes | Skips wizard, runs analysis with UI |
| uxlint | ✅ Yes | Runs analysis in CI mode (headless) |
| uxlint | ❌ No | Shows error and exits |
Authentication
uxlint supports cloud-based features through UXLint Cloud authentication. Authentication is optional for local-only usage but required for cloud features like collaborative reports and advanced AI models.
Authentication commands
uxlint auth login
Authenticate with UXLint Cloud using OAuth 2.0.
uxlint auth loginThe CLI will:
- Open your default browser to the UXLint Cloud authorization page
- Wait for you to complete authentication in the browser
- Securely store your credentials in your system's keychain
- Confirm successful login
Browser fallback: If the browser fails to open automatically, the CLI displays the authorization URL for manual copy-paste.
Already logged in: If you're already authenticated, the CLI notifies you and offers the option to re-authenticate.
uxlint auth status
Check your current authentication status and view user information.
uxlint auth statusDisplays:
- Authentication status (Authenticated/Expired/Not logged in)
- User name and email
- Organization (if applicable)
- Token expiration time
- Available cloud features based on your scopes
Example output (authenticated):
✓ Authenticated
User: John Doe ([email protected])
Organization: Acme Inc
Token expires: 2025-12-21 14:30:00
Available features: Cloud Reports, Team Collaboration, Advanced AI ModelsExample output (not logged in):
⚠ Not logged in
You are not currently authenticated with UXLint Cloud.
Run 'uxlint auth login' to authenticate.uxlint auth logout
Log out from UXLint Cloud and clear stored credentials.
uxlint auth logoutThis command:
- Removes your session from the system keychain
- Clears any cached authentication data
- Confirms successful logout
Security
- Secure storage: Credentials are stored in your operating system's native keychain:
- macOS: Keychain
- Windows: Credential Manager
- Linux: Secret Service API (e.g., gnome-keyring)
- OAuth 2.0 PKCE: Uses industry-standard OAuth 2.0 with PKCE (Proof Key for Code Exchange) for enhanced security
- Automatic token refresh: Access tokens are automatically refreshed when needed, with no user intervention
- Local-only logging: All authentication events are logged to local files only, never to stdout or external services
Examples
Complete authentication flow:
# Login to UXLint Cloud
uxlint auth login
# Opens browser, complete authentication, returns to CLI
# Check authentication status
uxlint auth status
# Shows: Authenticated, user info, token expiration
# Use cloud features in analysis (coming soon)
uxlint --cloud
# Logout when done
uxlint auth logout
# Confirms: Logged out successfullyHandling errors:
If authentication fails, the CLI provides clear error messages:
- Network errors: "Network error: Please check your internet connection and try again"
- User cancellation: "Authentication cancelled"
- Expired tokens: "Session expired: Please run 'uxlint auth login' to re-authenticate"
Ctrl+C cancellation: Press Ctrl+C at any time during authentication to cleanly cancel the operation.
What is measured, and what is judged
A report contains two kinds of statement, and it says which is which on every finding.
Measured. Each page is audited for accessibility and traced for
performance before the model is asked anything. Violations become findings
directly, carrying the rule that caught them (color-contrast, image-alt),
how many elements failed, and a severity derived from the rule's own impact
rating by a fixed table — critical → critical, serious → high,
moderate → medium, minor → low. The wording is the audit's own; nothing
labelled measured contains a sentence uxlint or a model wrote.
AI judgement. Everything measurement cannot reach — whether the wording makes sense, whether the flow suits the persona, whether the information architecture matches how someone thinks. The model is told what was measured so it does not report the same defect a second time as a guess, and it writes one note per page about what the measured violations mean for your persona. That note is rendered as judgement, outside the findings it discusses.
The model is never asked to judge performance. It cannot see a paint timing, and a severity assigned to something unobservable is a guess — which is what this measurement replaced.
What the numbers are
The statistics table carries, per page, the accessibility score and the measured Largest Contentful Paint and Cumulative Layout Shift. A measurement that was not taken says so, with the reason, rather than rendering as a blank or a zero — "audited and clean" and "never audited" are different facts.
First Contentful Paint is not reported. The tracing tool does not measure one, and the only FCP figure it carries is a projected saving from a suggested fix.
Accessibility is audited without reloading the page, so it describes the same page load the rest of the analysis read. The companion scores (SEO, best practices) are taken in that same mode and are labelled accordingly, because it skips the audits that need a fresh navigation — do not compare them with a score from a full page load.
What it costs
Measurement adds roughly 6 to 8 seconds per page: about 2 seconds for the audit and 6 for the trace, of which 5 is a fixed wait the tracing tool performs by design. A measurement that has not returned after 60 seconds is abandoned; that page is reported as not measured and the run continues.
Configuration
Configuration file
uxlint reads one of the following files from the current working directory (CWD):
.uxlintrc.yml.uxlintrc.json
When is a config file required?
- ✅ CI mode (
uxlintwithout--interactive): Config file is required - ✅ Interactive mode (
uxlint --interactive): Config file is optional- If present: Wizard is skipped, analysis starts immediately
- If absent: Wizard launches to create configuration
Creating a config file:
- Interactive wizard: Run
uxlint --interactiveand choose to save the configuration - Manual creation: Create
.uxlintrc.ymlor.uxlintrc.jsonin your project root (see schema below)
Schema
Required fields are marked as required. All text fields accept natural language.
mainPageUrl(string, required): The primary entry URL of your app.subPageUrls(string[], required): Additional pages to analyze.pages(array, required): Per-page descriptions to guide analysis.url(string, required): Page URL, must match one of the listed URLs.features(string, required): Freeform description of key tasks/flows/components on the page.
persona(string, required): Can be a short paragraph describing goals, motives, accessibility needs, devices, constraints, etc.report(object, required): Report output configuration.output(string, required): File path where the report will be written (e.g.,./ux-report.md).
thresholds(object, optional): CI gate limits. See Failing CI on UX regressions.browser(object, optional): Browser settings. See Browser requirements.analysis(object, optional): Analysis settings. See Analysis settings.pageTimeLimitMs(number, optional): Per-page wall-clock limit in milliseconds (default600000).
Note: AI configuration has been moved to environment variables for security. See Environment Variables section below.
Failing CI on UX regressions
By default a run always exits 0 — it reports, it does not gate. Add a thresholds block to make the pipeline fail when a run crosses a limit you set.
Upgrading from 4.3 or earlier? Measured accessibility findings count toward these thresholds on the same terms as any other finding, so a run can now fail on a site that has not changed. Two things to expect: measured findings are typically more numerous than the ones the model used to guess at, and one site-wide defect can exhaust a threshold on its own — a single bad contrast rule on ten pages is ten findings, and the gate counts ten. The report's Recurring across pages table makes that visible, but it does not change the count. Re-tune your thresholds against one real run before turning the gate on.
thresholds:
maxCritical: 0 # no critical findings permitted
maxHigh: 3 # at most three high findings
maxMedium: 10
maxLow: 20
failOnPartialPage: true # a page cut short before finishing fails the run
failOnFailedPage: true # a page that could not be analysed fails the run{
"thresholds": {
"maxCritical": 0,
"maxHigh": 3,
"failOnFailedPage": true
}
}Every key is optional, and each behaves as follows:
| | |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| No thresholds key at all | The gate is off. Exit status is unchanged from before this feature existed. |
| A severity key you leave out | That severity is not gated. |
| maxCritical: 0 | Any critical finding fails the run. Absent and 0 are different: absent means "not gated", 0 means "none permitted". |
| A count equal to the limit | Passes. Limits are inclusive maximums, so maxHigh: 3 admits exactly three. |
| failOnPartialPage / failOnFailedPage | Default to true once thresholds is present. A verdict resting on pages that never finished is not evidence, so they are on unless you turn them off. |
| No page analysed successfully | Always fails, whatever you configured. |
Findings are counted across every page, including ones that were cut short or failed — a page that found a critical issue and then crashed still found it.
A failing run prints why, so the CI log alone is enough to diagnose it:
uxlint: gate failed
critical 2 findings, limit 0
high 3 findings, limit 1
failed 1 page could not be analysed
https://shop.example/checkout — navigation timed out after 30sPages are listed whether or not you gated on them. A line for a flag you
switched off is marked (not gated), so it cannot be mistaken for the reason
the run failed.
A passing run prints what it checked, so an active gate is visible in a green log:
uxlint: gate passed
critical 0 findings, limit 0
high 1 findings, limit 3The report file is always written, pass or fail.
Interactive mode is unaffected. uxlint --interactive shows the same verdict but never changes its exit status — a person watching a terminal already sees the findings.
Typos are rejected before analysis starts. An unrecognised key, a negative limit, or a non-integer stops the run in under a second with no browser launched and no model call made:
$ uxlint
uxlint: thresholds.maxCritcal is not a recognised threshold. Expected one of:
maxCritical, maxHigh, maxMedium, maxLow, failOnPartialPage, failOnFailedPageA key that was merely ignored would leave you believing you had a gate when you had none.
Environment Variables
uxlint uses environment variables for sensitive configuration like API keys. Create a .env file in your project root (see .env.example for reference).
AI Provider Configuration (Required)
All AI configuration is done via environment variables to keep sensitive data out of version control:
UXLINT_AI_PROVIDER(required): AI provider to use. One of:anthropic,openai,ollama,xai,google.UXLINT_AI_API_KEY(required for all providers exceptollama): API key for the selected provider.UXLINT_AI_MODEL(optional): AI model name. Defaults vary by provider (see below).UXLINT_AI_BASE_URL(optional, only forollama): Ollama server base URL. Defaults tohttp://localhost:11434/api.
Supported providers:
Anthropic (default):
- Set
UXLINT_AI_PROVIDER=anthropic - Requires
UXLINT_AI_API_KEY - Default model:
claude-sonnet-4-5-20250929 - Get your API key from https://console.anthropic.com/
- Set
OpenAI:
- Set
UXLINT_AI_PROVIDER=openai - Requires
UXLINT_AI_API_KEY - Default model:
gpt-5 - Get your API key from https://platform.openai.com/api-keys
- Set
Ollama (local):
- Set
UXLINT_AI_PROVIDER=ollama - Does not require
UXLINT_AI_API_KEY - Optional
UXLINT_AI_BASE_URL(default:http://localhost:11434/api) - Default model:
qwen3-vl - Requires Ollama to be installed and running locally
- ⚠️ Important: The model must support both vision (multimodal) and tool calling
- ✅ Recommended:
qwen3-vl,qwen2-vl:7b,qwen2-vl:2b - ❌ Not supported:
llama3.2-vision(no tool calling),llama3.1(no vision)
- ✅ Recommended:
- Set
xAI (Grok):
- Set
UXLINT_AI_PROVIDER=xai - Requires
UXLINT_AI_API_KEY - Default model:
grok-4 - Get your API key from https://x.ai/
- Set
Google (Gemini):
- Set
UXLINT_AI_PROVIDER=google - Requires
UXLINT_AI_API_KEY - Default model:
gemini-2.5-pro - Get your API key from https://ai.google.dev/
- Set
Example .env file:
# AI Provider Configuration
UXLINT_AI_PROVIDER=anthropic
UXLINT_AI_API_KEY=sk-ant-your-api-key-here
UXLINT_AI_MODEL=claude-sonnet-4-5-20250929 # optionalCloud/OAuth Configuration (Optional)
Authentication can be configured using environment variables:
UXLINT_CLOUD_CLIENT_ID: OAuth client ID (optional, uses default if not set)UXLINT_CLOUD_API_BASE_URL: UXLint Cloud API base URL (optional, defaults to production URL)UXLINT_CLOUD_REDIRECT_URI: OAuth redirect URI (optional, defaults tohttp://localhost:8080/callback)
These variables are typically not needed unless you're using a custom UXLint Cloud instance.
Example: YAML
mainPageUrl: 'https://github.com'
subPageUrls:
- 'https://github.com/login'
- 'https://github.com/explore'
- 'https://github.com/pricing'
- 'https://github.com/signup'
pages:
- url: 'https://github.com'
features: >-
GitHub landing page. User interactions: 1. Scroll down to view features
section showcasing code hosting, collaboration tools, and integrations. 2.
Click "Sign up" button located in the top right corner to navigate to
signup page. 3. Use top navigation menu to access "Product", "Solutions",
"Pricing", and "Enterprise" pages. 4. View trending repositories section
showing popular open source projects. 5. Use search bar at the top to
search for repositories, users, or topics.
- url: 'https://github.com/login'
features: >-
GitHub login page. User interaction steps: 1. Locate the username or email
input field and type your GitHub username or email address. 2. Locate the
password input field and type your password. 3. Optionally check the
"Remember me" checkbox to stay logged in. 4. Click the "Sign in" button to
submit the form. If two-factor authentication is enabled, enter the 2FA
code when prompted. After successful login, user will be redirected to
their dashboard.
- url: 'https://github.com/explore'
features: >-
GitHub Explore page showing trending repositories and topics. User
interactions: 1. Browse trending repositories: Scroll through the list of
trending repositories showing repository name, description, language, and
star count. Click on any repository to view its details. 2. Explore topics:
Click on topic tags to see repositories related to that topic. Topics are
displayed as clickable badges. 3. Filter by language: Use the language
filter dropdown to filter repositories by programming language (e.g.,
JavaScript, Python, Java). 4. View collections: Scroll to see curated
collections of repositories organized by theme or purpose. Click on a
collection to view its contents. 5. Search: Use the search bar at the top
to search for specific repositories, users, or topics.
- url: 'https://github.com/pricing'
features: >-
GitHub pricing page displaying subscription plans. User interactions: 1.
View pricing tiers: The page displays pricing cards for Free, Team, and
Enterprise plans with feature comparisons. Each plan shows monthly and
annual pricing. 2. Toggle billing period: Click the toggle switch or
buttons to switch between monthly and annual billing. Prices update
automatically to show discounts for annual plans. 3. Compare features: Scroll
down to view detailed feature comparison table showing what's included in
each plan. 4. Select a plan: Click "Get started with Team" or "Contact
Sales" button on a pricing card to proceed with that plan. 5. View FAQ:
Scroll down to view FAQ section about billing, plan features, and
migration. Click on FAQ items to expand and view answers.
- url: 'https://github.com/signup'
features: >-
GitHub signup page for new user registration. User interaction steps: 1.
Enter username: Locate the username input field and type a desired
username. The system will check availability in real-time and show
feedback. 2. Enter email address: Locate the email input field and type an
email address. 3. Enter password: Locate the password field and type a
password. Observe the password strength indicator showing requirements
(e.g., at least 8 characters, one lowercase letter, one number). 4. Email
preferences: Optionally check/uncheck boxes for receiving product updates
and announcements. 5. Verify account: Check the "Verify your account"
puzzle or CAPTCHA if presented. 6. Submit form: Click "Create account"
button to submit the registration. A verification email will be sent to
the provided email address. Click the link in the email to verify and
complete registration.
persona: >-
You are a developer looking to host your open source project on GitHub. You
want to understand how easy it is to get started, explore existing projects,
and set up your repository. Your approach: First, visit the pricing page to
understand what features are available in the free plan. Next, explore the
Explore page to see what kinds of projects are popular and get inspiration.
Then, sign up for a free account to start hosting your own projects. Finally,
log in to access your dashboard and create your first repository.
report:
output: './ux-report.md'
thresholds:
maxCritical: 0
maxHigh: 3Example: JSON
{
"mainPageUrl": "https://github.com",
"subPageUrls": [
"https://github.com/login",
"https://github.com/explore",
"https://github.com/pricing",
"https://github.com/signup"
],
"pages": [
{
"url": "https://github.com",
"features": "GitHub landing page. User interactions: 1. Scroll down to view features section showcasing code hosting, collaboration tools, and integrations. 2. Click \"Sign up\" button located in the top right corner to navigate to signup page. 3. Use top navigation menu to access \"Product\", \"Solutions\", \"Pricing\", and \"Enterprise\" pages. 4. View trending repositories section showing popular open source projects. 5. Use search bar at the top to search for repositories, users, or topics."
},
{
"url": "https://github.com/login",
"features": "GitHub login page. User interaction steps: 1. Locate the username or email input field and type your GitHub username or email address. 2. Locate the password input field and type your password. 3. Optionally check the \"Remember me\" checkbox to stay logged in. 4. Click the \"Sign in\" button to submit the form. If two-factor authentication is enabled, enter the 2FA code when prompted. After successful login, user will be redirected to their dashboard."
},
{
"url": "https://github.com/explore",
"features": "GitHub Explore page showing trending repositories and topics. User interactions: 1. Browse trending repositories: Scroll through the list of trending repositories showing repository name, description, language, and star count. Click on any repository to view its details. 2. Explore topics: Click on topic tags to see repositories related to that topic. Topics are displayed as clickable badges. 3. Filter by language: Use the language filter dropdown to filter repositories by programming language (e.g., JavaScript, Python, Java). 4. View collections: Scroll to see curated collections of repositories organized by theme or purpose. Click on a collection to view its contents. 5. Search: Use the search bar at the top to search for specific repositories, users, or topics."
},
{
"url": "https://github.com/pricing",
"features": "GitHub pricing page displaying subscription plans. User interactions: 1. View pricing tiers: The page displays pricing cards for Free, Team, and Enterprise plans with feature comparisons. Each plan shows monthly and annual pricing. 2. Toggle billing period: Click the toggle switch or buttons to switch between monthly and annual billing. Prices update automatically to show discounts for annual plans. 3. Compare features: Scroll down to view detailed feature comparison table showing what's included in each plan. 4. Select a plan: Click \"Get started with Team\" or \"Contact Sales\" button on a pricing card to proceed with that plan. 5. View FAQ: Scroll down to view FAQ section about billing, plan features, and migration. Click on FAQ items to expand and view answers."
},
{
"url": "https://github.com/signup",
"features": "GitHub signup page for new user registration. User interaction steps: 1. Enter username: Locate the username input field and type a desired username. The system will check availability in real-time and show feedback. 2. Enter email address: Locate the email input field and type an email address. 3. Enter password: Locate the password field and type a password. Observe the password strength indicator showing requirements (e.g., at least 8 characters, one lowercase letter, one number). 4. Email preferences: Optionally check/uncheck boxes for receiving product updates and announcements. 5. Verify account: Check the \"Verify your account\" puzzle or CAPTCHA if presented. 6. Submit form: Click \"Create account\" button to submit the registration. A verification email will be sent to the provided email address. Click the link in the email to verify and complete registration."
}
],
"persona": "You are a developer looking to host your open source project on GitHub. You want to understand how easy it is to get started, explore existing projects, and set up your repository. Your approach: First, visit the pricing page to understand what features are available in the free plan. Next, explore the Explore page to see what kinds of projects are popular and get inspiration. Then, sign up for a free account to start hosting your own projects. Finally, log in to access your dashboard and create your first repository.",
"report": {
"output": "./ux-report.md"
},
"thresholds": {
"maxCritical": 0,
"maxHigh": 3
}
}uxlint CLI State Machine
The CLI uses an XState state machine to manage execution flow. The behavior depends on the --interactive flag and configuration file presence:
stateDiagram-v2
[*] --> IDLE
IDLE --> TTY: --interactive flag is present
IDLE --> CI: --interactive flag is not present
%% TTY branch (Interactive mode)
TTY --> Wizard: uxlintrc file is not present
TTY --> AnalyzeWithUI: uxlintrc file is present
Wizard --> AnalyzeWithUI: uxlintrc file is created
%% CI branch (Headless mode)
CI --> AnalyzeWithoutUI: uxlintrc file is present
CI --> Error: uxlintrc file is not present
%% After analysis, report is created
AnalyzeWithUI --> ReportBuilder: UxReport is created
AnalyzeWithoutUI --> ReportBuilder: UxReport is created
ReportBuilder --> [*]State descriptions
- IDLE: Initial state, determines mode based on
--interactiveflag - TTY (Interactive mode): Uses Ink UI components
- Wizard: Interactive configuration wizard (when no config file exists)
- AnalyzeWithUI: Analysis with visual progress indicators
- CI (Headless mode): No UI, uses
console.logoutput- AnalyzeWithoutUI: Headless analysis execution
- Error: Missing configuration error state
- ReportBuilder: Generates final markdown report
- Done: Final state, exits with appropriate exit code
Mapping to usage scenarios
| Scenario | Command | Initial State | Final State |
| --------------- | ------------------------------------ | ---------------------------- | -------------------- |
| Wizard | uxlint --interactive (no config) | IDLE → TTY → Wizard | ReportBuilder → Done |
| Direct analysis | uxlint --interactive (with config) | IDLE → TTY → AnalyzeWithUI | ReportBuilder → Done |
| CI mode | uxlint (with config) | IDLE → CI → AnalyzeWithoutUI | ReportBuilder → Done |
| Error | uxlint (no config) | IDLE → CI → Error | Done (exit code 1) |
Roadmap
- Richer report sections tailored for frontend implementation
- Deeper task and heuristic coverage
- Expanded guidance for accessibility and performance trade-offs
Contributing
Issues and pull requests are welcome.
License
MIT
