From ac
Maestro QA workflow patterns and MCP tool integration. Loaded by /ac:maestro-qa command.
npx claudepluginhub anilcancakir/claude-code-plugin --plugin acThis skill uses the workspace's default tool permissions.
Mobile QA testing via Maestro CLI's built-in MCP server. This skill provides workflow patterns, token efficiency strategies, and self-healing patterns used by the `/ac:maestro-qa` command. Report format lives in `references/report-format.md`. Shared cross-backend patterns (knowledge system, test modes, parallel execution, evidence persistence) live in the plugin-level `../../references/qa-patte...
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
Mobile QA testing via Maestro CLI's built-in MCP server. This skill provides workflow patterns, token efficiency strategies, and self-healing patterns used by the /ac:maestro-qa command. Report format lives in references/report-format.md. Shared cross-backend patterns (knowledge system, test modes, parallel execution, evidence persistence) live in the plugin-level ../../references/qa-patterns.md — read it for conventions shared with browser-qa and flutter-qa. This file distills orchestration knowledge and MCP-specific patterns.
brew install maestrocurl -Ls "https://get.maestro.mobile.dev" | bashmaestro --versionUser adds Maestro MCP server to .mcp.json:
{
"maestro": {
"command": "maestro",
"args": ["mcp"]
}
}
MCP tools communicate over stdio JSON-RPC — each tool call is a single request/response. View hierarchy returns CSV (element_num, depth, attributes, parent_num) — token-efficient by design. Never dump full CSV into context; parse for target elements only.
mcp__maestro__list_devices to discover available simulators/emulatorsmcp__maestro__start_device with device_id or platform (ios/android)Priority order for mcp__maestro__tap_on:
id: — testID / accessibilityIdentifier (most stable, preferred)text: — visible label (fuzzy matching enabled by default)index: — positional disambiguation when multiple matches existenabled, checked, focused, selected for narrowingPlatform-specific ID mapping:
testID prop works as id: on both iOS and AndroidcontentDescription for accessibility, testTag for Jetpack Compose.accessibilityIdentifier() (SwiftUI), accessibilityIdentifier property (UIKit)Combined filters: mcp__maestro__tap_on(device_id, text: "Item", index: 2, enabled: true)
| Tool | Purpose | Key Params |
|---|---|---|
mcp__maestro__list_devices | List available simulators and emulators | none |
mcp__maestro__start_device | Start a simulator or emulator | device_id (string, optional) OR platform (string: ios/android, optional) — provide one |
| Tool | Purpose | Key Params |
|---|---|---|
mcp__maestro__launch_app | Launch app on device | device_id (required), appId (required) |
mcp__maestro__stop_app | Stop app on device | device_id (required), appId (required) |
| Tool | Purpose | Key Params |
|---|---|---|
mcp__maestro__tap_on | Tap a UI element | device_id (required), at least one of: text (string), id (string), index (int). Optional: use_fuzzy_matching (bool, default true), enabled (bool), checked (bool), focused (bool), selected (bool) |
mcp__maestro__input_text | Type into focused field | device_id (required), text (required) |
mcp__maestro__back | Press hardware back button | device_id (required) |
| Tool | Purpose | Key Params |
|---|---|---|
mcp__maestro__inspect_view_hierarchy | Get screen elements as CSV | device_id (required). Returns: element_num, depth, attributes, parent_num — CSV format, token-efficient |
mcp__maestro__take_screenshot | Capture screen as PNG | device_id (required) |
| Tool | Purpose | Key Params |
|---|---|---|
mcp__maestro__run_flow | Execute inline YAML commands | device_id (required), flow_yaml (required, string), env (optional, object). Accepts single command or full flow with headers |
mcp__maestro__run_flow_files | Execute YAML flow files from disk | device_id (required), flow_files (required, comma-separated paths), env (optional, object) |
mcp__maestro__check_flow_syntax | Validate YAML flow syntax | flow_yaml (required) |
| Tool | Purpose | Key Params |
|---|---|---|
mcp__maestro__cheat_sheet | Get Maestro command reference | none |
mcp__maestro__query_docs | Query Maestro documentation | question (required) |
mcp__maestro__run_flow is the workhorse for multi-step batching and assertions. Pass inline YAML:
Single command:
- tapOn: Login
Multi-step batch (form fill):
- tapOn:
id: "email_field"
- inputText: "user@example.com"
- tapOn:
id: "password_field"
- inputText: "secretpass"
- tapOn:
id: "login_button"
Assertions:
- assertVisible: "Welcome back"
- assertTrue:
condition: "${output.loggedIn} == true"
Clear state launch (fresh app start):
- clearState: com.example.app
- launchApp: com.example.app
Video recording (YAML flow commands, NOT MCP tools):
- startRecording: test-evidence
- tapOn: Login
- inputText: "user@test.com"
- stopRecording
startRecording and stopRecording are Maestro YAML flow commands executed inside run_flow — they are NOT standalone MCP tools. Use sparingly, only for bug reproduction evidence.
mcp__maestro__list_devices to find available simulators/emulators. mcp__maestro__start_device if none runningmcp__maestro__launch_app with target appId on the selected device_idmcp__maestro__inspect_view_hierarchy returns CSV of current screen. Parse for target elements only — never dump full CSV into contextmcp__maestro__tap_on, mcp__maestro__input_text, mcp__maestro__back. Re-inspect after each action (observe-act-observe)mcp__maestro__inspect_view_hierarchy after error-likely interactions (form submits, navigation, assertions)mcp__maestro__take_screenshot + mcp__maestro__inspect_view_hierarchy on every FAILWhen running in parallel mode, each agent uses its own device_id from the device pool. Devices are fully isolated — no cross-agent state bleed.
mcp__maestro__stop_app + clear state via mcp__maestro__run_flow (- clearState: <appId> + - launchApp: <appId>) per bug to avoid state pollutionmcp__maestro__take_screenshot + mcp__maestro__inspect_view_hierarchy. Evidence is mandatory for FAIL verdictsKey: Isolation is paramount. Each bug gets a fresh clear-state launch cycle. If bug doc lacks structure, extract bugs by paragraph/section breaks.
When running in parallel mode, each agent uses its own device_id. stop_app + clearState + launchApp per bug on that device.
Done when: blocks from plan file. Fall back to bulleted checklist itemsmcp__maestro__launch_app, mcp__maestro__inspect_view_hierarchy, interact by id/text, assertions via mcp__maestro__run_flow (- assertVisible:, - assertTrue:)mcp__maestro__inspect_view_hierarchy to confirm UI state matches expectationsKey: Use mcp__maestro__run_flow with assertVisible / assertTrue for programmatic assertions. Clean state per test case via stop_app + clearState + launchApp.
When running in parallel mode, each agent uses its own device_id for all MCP calls in that agent's scope.
.ac/maestro-qa/{testName}.json (testName derived from original target) — stop if not foundKey: Output a diff table showing previous to current verdict changes.
When running in parallel mode, each agent uses its own device_id to keep re-run sessions isolated from any concurrently running agents.
.maestro/) via Globmcp__maestro__check_flow_syntax for each flow filemcp__maestro__run_flow_files with comma-separated paths. Pass env object if environment variables neededKey: No flow generation — runs existing .maestro/ flows only. Use mcp__maestro__run_flow_files for batch execution, not mcp__maestro__run_flow with inline YAML.
When running in parallel mode, each agent runs a subset of flow files on its own device_id.
inspect_view_hierarchy — returns CSV (element_num, depth, attributes, parent_num). Parse for target elements only; never dump full CSV output into contexttake_screenshot — saved to disk, only paths in context. Screenshots are FAIL evidence only — do not screenshot after every steprun_flow for multi-step batching — replaces N individual MCP tool calls with 1 inline YAML block. Use for form fills, assertion sequences, clear-state launchesmcp__maestro__stop_app + mcp__maestro__launch_app to prevent context bloat from accumulated tool responsesrun_flow — startRecording/stopRecording are YAML flow commands inside run_flow, not separate MCP tools. Use sparingly — only for bug reproduction evidence where screenshots alone are insufficientWhen an element interaction fails (element not found, selector mismatch, stale state):
mcp__maestro__inspect_view_hierarchy to get fresh CSV of current screen stateid: first, then text: with fuzzy matching enabled, then parent-relative context from CSV hierarchy. Check EFFECTIVE_KNOWLEDGE for known selectors that survived previous retriesmcp__maestro__tap_on with new id, text, or index parametersBLOCKED with note: "Element not found after 3 retries: [description]"Never fall back to coordinate-based selectors (point: "50%,50%") — they are brittle and break across device sizes, orientations, and platform differences. id: and text: selectors are the only acceptable targeting strategies.
During a test run, capture non-obvious discoveries that would save the next agent time. Do not capture trivial facts (e.g., "app has a tab bar" — the next agent can see that). Only capture what required effort to discover.
Before executing any test cases, load existing project knowledge:
.ac/qa/knowledge/project.jsonl via Read tool. If the file doesn't exist, proceed with empty knowledge.PRIOR_KNOWLEDGE from the parent command (if provided). On same-key conflict, file-based knowledge wins.EFFECTIVE_KNOWLEDGE — use throughout execution for selector hints, timing guidance, permission dialog handling, and navigation awareness.Project knowledge is cumulative across all test runs. A fact learned during ad-hoc testing of the login screen benefits a later plan-verify run that touches the same flows.
myapp://path), tab bar structure, drawer navigation paths, back stack behavior{"type": "selector|flow|timing|gotcha|permission|navigation", "key": "<kebab-case-id>", "value": "<what to remember>", "confidence": "high|medium"}
Anti-pattern: Do not log obvious/trivial facts. If the next agent would discover it in one hierarchy inspect, skip it. Only capture discoveries that required multiple attempts or non-obvious reasoning to reach.
Write facts to disk immediately after each test case — do not wait until the end of the run.
Write pattern (via Bash — agent has no Write tool):
mkdir -p .ac/qa/knowledge/
echo '{"type":"selector","key":"login-btn","value":"id:login_button works, text:Login flaky on Android","confidence":"high"}' >> .ac/qa/knowledge/.mqa-{SESSION_NAME}.jsonl
File naming: .mqa-{SESSION_NAME}.jsonl — each agent writes to its own temp file. Parent merges all temp files into project.jsonl after execution.
When to write:
high or medium confidenceWhy immediate writes matter:
${CLAUDE_PLUGIN_ROOT}/skills/maestro-qa/references/report-format.mdLoad report-format.md for the structured JSON schema used in .ac/maestro-qa/{testName}.json persistence.
| Anti-Pattern | Why Wrong | Do Instead |
|---|---|---|
| Dumping full hierarchy CSV into context | Wastes tokens — CSV can be large on complex screens | Parse CSV for target elements only |
| Screenshots when hierarchy suffices | take_screenshot returns image data, costs tokens | Use inspect_view_hierarchy; screenshots only as FAIL evidence |
| 20+ interactions without app restart | Accumulated state may cause flakiness | stop_app + launch_app after ~20 interactions |
Hardcoded coordinates (point: "50%,50%") | Brittle — breaks across devices, orientations, platforms | Use id: or text: selectors exclusively |
| Skipping evidence on FAIL | Unverifiable failures waste debugging time | take_screenshot + inspect_view_hierarchy on every FAIL |
| One MCP call per form field | N round trips wastes time and tokens | Batch with run_flow inline YAML |
| Waiting until end to write knowledge | Facts lost on crash, parallel agents can't benefit mid-run | Write to .mqa-{SESSION_NAME}.jsonl after each test case |
| Using Maestro Studio for element discovery | Browser-based UI, not agent-drivable | Use inspect_view_hierarchy MCP tool |