Agent skill

Composing Semantics Matchers

by skydoves in skydoves/android-testing-skills

A skill your agent uses to build precise Compose UI test queries by composing SemanticsMatcher predicates with infix and, infix or, and operator not, plus the prebuilt filter library (hasText…

Apache-2.0Auto-check passedMobile

Install Composing Semantics Matchers

skills CLI
$ npx skills add skydoves/android-testing-skills --skill composing-semantics-matchers -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install skydoves/android-testing-skills composing-semantics-matchers --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/skydoves/android-testing-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/compose/finders/composing-semantics-matchers .claude/skills/composing-semantics-matchers && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
composing-semantics-matchers
GitHub stars
333
Token cost
~3.2k tokens
SKILL.md length
847 words
Files
1
Skills in repo
50
Repo updated
First seen
Licence
Apache-2.0

At a glance

A skill your agent uses to build precise Compose UI test queries by composing SemanticsMatcher predicates with infix and, infix or, and operator not, plus the prebuilt filter library (hasText…

  • Build precise Compose UI test queries by composing SemanticsMatcher predicates with infix and
  • SKILL.md covers When to use this skill, When NOT to use this skill, Prerequisites and Workflow, plus 4 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md
  • Plus the prebuilt filter library (hasText

What it does

Composing Semantics Matchers is an agent skill from skydoves/android-testing-skills. Use this skill to build precise Compose UI test queries by composing SemanticsMatcher predicates with infix and, infix or, and operator not, plus the prebuilt filter library (hasText, hasClickAction, isEnabled, isOn, hasTestTag, hasContentDescription, hasParent, hasAnyAncestor, hasAnyChild, hasAnySibling, hasAnyDescendant, hasImeAction, hasScrollToKeyAction, hasScrollToNodeAction, isDialog, isPopup, isRoot, isFocused, isEditable, isHeading). Covers SemanticsMatcher.expectValue / keyIsDefined / keyNotDefined for…

Its SKILL.md is about 3.2k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Mobile. The repository describes itself as: ⚡️ A set of skills for Android testing: Compose UI, AndroidX Test, JVM unit tests, and ADB. The licence is Apache-2.0.

When your agent uses it

  • Build precise Compose UI test queries by composing SemanticsMatcher predicates with infix and
  • Plus the prebuilt filter library (hasText
  • HasContentDescription
  • HasAnyDescendant

Example prompts

  • “an enabled button with text Submit”
  • “/composing-semantics-matchers”

What it can do on your machine

Read from SKILL.md and the folder at commit 8665ed5. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are kotlin).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Links to these hosts (documentation or services it may open):

    • developer.android.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Composing Semantics Matchers loads about 3.2k tokens when it runs. Until then it costs about 240 tokens; SKILL.md has 847 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~240
When it runs · the whole SKILL.md, loaded when a task matches
~3.2k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from skydoves/android-testing-skills at commit 8665ed5, republished under its Apache-2.0 licence (© skydoves). 847 words, ~3,204 tokens.

Download SKILL.mdSave it as .claude/skills/composing-semantics-matchers/SKILL.md (or your agent's skills folder).
name
composing-semantics-matchers
description
Use this skill to build precise Compose UI test queries by composing `SemanticsMatcher` predicates with `infix and`, `infix or`, and `operator not`, plus the prebuilt filter library (`hasText`, `hasClickAction`, `isEnabled`, `isOn`, `hasTestTag`, `hasContentDescription`, `hasParent`, `hasAnyAncestor`, `hasAnyChild`, `hasAnySibling`, `hasAnyDescendant`, `hasImeAction`, `hasScrollToKeyAction`, `hasScrollToNodeAction`, `isDialog`, `isPopup`, `isRoot`, `isFocused`, `isEditable`, `isHeading`). Covers `SemanticsMatcher.expectValue` / `keyIsDefined` / `keyNotDefined` for custom semantics keys. Use when the developer asks how to find "an enabled button with text Submit", how to combine matchers, how to filter by a custom `SemanticsPropertyKey`, how to write a hierarchical predicate, or mentions `hasParent`, `hasAnyAncestor`, `expectValue`. If the developer wants one matcher instead of three chained assertions, use this skill.
license
Apache-2.0. See LICENSE for complete terms.
metadata.author
Jaewoong Eum (skydoves)
metadata.keywords
jetpack-compose, ui-testing, SemanticsMatcher, hasText, hasClickAction, hasParent, hasAnyAncestor, expectValue, matcher-algebra

Composing Semantics Matchers — One Matcher, One Error

A SemanticsMatcher is a description string plus a (SemanticsNode) -> Boolean predicate (SemanticsMatcher.kt:26). Compose ships with a rich filter library and three combinators (and, or, not) that produce a single matcher whose error message lists every clause. This skill picks the right factory, composes precise predicates, and replaces brittle assertion chains.

When to use this skill

  • The developer wants to find "an enabled Button with text Submit" or any node matching multiple constraints.
  • The developer asks how to combine hasText and hasClickAction, or how to negate a matcher with not.
  • The developer needs to filter by a custom SemanticsPropertyKey (e.g. a domain-specific role) using expectValue/keyIsDefined.
  • The developer asks about hierarchical matchers like hasParent, hasAnyAncestor, hasAnyChild, hasAnySibling, hasAnyDescendant.
  • A test chains multiple assertIs* calls and the developer wants a single, declarative predicate.

When NOT to use this skill

  • The query is "find by tag/text/content description only" — use ../finding-nodes-by-tag-text-content/SKILL.md.
  • The right node exists but only as a relative — use ../traversing-the-semantics-tree/SKILL.md.
  • The matcher is fine; only the assertions need rework — see ../../assertions/asserting-node-state-and-text/SKILL.md.

Prerequisites

  • androidx.compose.ui:ui-test on the test classpath. See ../../setup/configuring-test-dependencies/SKILL.md if unresolved.
  • Comfort with Modifier.semantics { … } in production code. Custom keys must be set via Modifier.semantics { customKey = value } to be matchable from tests.

Workflow

  • 1. Build matchers from the prebuilt filter library. Every prebuilt matcher lives in commonMain/.../Filters.kt. Group by signal:

    SignalMatchersFile:line
    Enabled / disabledisEnabled(), isNotEnabled()Filters.kt:38-47
    Toggle (Switch, Checkbox)isToggleable(), isOn(), isOff()Filters.kt:54-70
    Selection (Tab, RadioButton)isSelectable(), isSelected(), isNotSelected()Filters.kt:77-93
    FocusisFocusable(), isNotFocusable(), isFocused(), isNotFocused()Filters.kt:100-122
    Click actionhasClickAction(), hasNoClickAction()Filters.kt:129-136
    Scroll actionhasScrollAction(), hasNoScrollAction(), hasScrollToIndexAction(), hasScrollToKeyAction(), hasScrollToNodeAction()Filters.kt:143-425
    Text actions (TextField)hasSetTextAction(), hasInsertTextAtCursorAction(), hasPerformImeAction(), hasImeAction(ImeAction)Filters.kt:365-392
    Focus actionhasRequestFocusAction()Filters.kt:399
    Content descriptionhasContentDescription(value, substring, ignoreCase), hasContentDescriptionExactly(vararg)Filters.kt:165-212
    TexthasText(text, substring, ignoreCase), hasTextExactly(vararg, includeEditableText=true)Filters.kt:229-293
    A11y / state metadatahasStateDescription, hasProgressBarRangeInfo, isHeading, isDialog, isPopup, isHiddenFromAccessibility, isEditable, isRootFilters.kt:301-439
    Test taghasTestTag(testTag)Filters.kt:326-327
    HierarchicalhasParent(matcher), hasAnyChild(matcher), hasAnySibling(matcher), hasAnyAncestor(matcher), hasAnyDescendant(matcher)Filters.kt:446-530

    hasText searches SemanticsProperties.Text, SemanticsProperties.EditableText, AND SemanticsProperties.InputText simultaneously (Filters.kt:229-258). hasContentDescription matches against the merged list of descriptions (Filters.kt:165-188).

  • 2. Compose with and / or / not. Combinators come from SemanticsMatcher.kt:60-74. Each produces a new matcher whose description reads (left) && (right) / (left) || (right) / NOT (inner). The framework prints this description verbatim on assertion failure, so the failure message shows exactly which clause(s) failed.

  • 3. Use SemanticsMatcher.expectValue for custom keys. When the production code declares a custom SemanticsPropertyKey<T> and writes it via Modifier.semantics { customKey = value }, match it with SemanticsMatcher.expectValue(customKey, expectedValue) (SemanticsMatcher.kt:33-37). For "this key is set at all", use SemanticsMatcher.keyIsDefined(customKey) (SemanticsMatcher.kt:40-42); for "this key is NOT set", use keyNotDefined (SemanticsMatcher.kt:45-47). Built-in matchers like isOn() are themselves thin wrappers over expectValue(SemanticsProperties.ToggleableState, On) (Filters.kt:61-62).

  • 4. Pass the composed matcher to onNode/onAllNodes. onNode(matcher, useUnmergedTree=false) and onAllNodes(matcher, useUnmergedTree=false) are the canonical entry points (SemanticsNodeInteractionsProvider.kt). Both onNodeWithTag and friends are convenience wrappers — drop them when the predicate gets richer.

  • 5. For hierarchical assertions, prefer hasAnyAncestor/hasAnyDescendant over multiple traversal steps. Example: "find the Text inside the dialog" → onNode(hasText("Discard?") and hasAnyAncestor(isDialog())). Cleaner than onAllNodes(isDialog()).onFirst().onChildren().filter(hasText(...)).onFirst().

Patterns

Pattern: replace assertion chains with a single matcher
kotlin
// WRONG
@Test
fun submit_isEnabledClickable() {
    rule.setContent { CheckoutScreen() }
    rule.onNodeWithText("Submit")
        .assertHasClickAction()
        .assertIsEnabled()
}
// WRONG because: each assertion is a separate fetch + error path. Failure prints "no click
// action" without telling the developer the matched node is the *enabled-but-wrong* button on
// a different screen.
kotlin
// RIGHT
@Test
fun submit_isEnabledClickable() {
    rule.setContent { CheckoutScreen() }
    rule.onNode(hasText("Submit") and hasClickAction() and isEnabled())
        .assertExists()
}

The composed matcher's description prints (Text + InputText + EditableText contains 'Submit' (ignoreCase: false)) && (OnClick is defined) && (is enabled) on failure, naming every unsatisfied clause.

Show full SKILL.md (330 more words)Show less
Pattern: hierarchical match — "the Text inside the dialog"
kotlin
// WRONG
rule.onAllNodes(isDialog())
    .onFirst()
    .onChildren()
    .filterToOne(hasText("Discard?"))
    .assertIsDisplayed()
// WRONG because: it implicitly assumes the Text is a direct child of the dialog root.
// AlertDialog wraps its body in Column/Surface, so the Text is a descendant, not a child.
kotlin
// RIGHT
rule.onNode(hasText("Discard?") and hasAnyAncestor(isDialog()))
    .assertIsDisplayed()
Pattern: negation and "exactly one"
kotlin
// "An enabled, non-toggleable Button (so: not a Switch or Checkbox) with text Submit"
rule.onNode(hasText("Submit") and isEnabled() and !isToggleable())
    .assertHasClickAction()

!matcher invokes operator fun not() (SemanticsMatcher.kt:72-74) — works on every matcher in the library.

Pattern: custom semantics key
kotlin
// production:
val PriorityKey = SemanticsPropertyKey<Int>("Priority")
var SemanticsPropertyReceiver.priority by PriorityKey

@Composable
fun TaskRow(task: Task) {
    Row(modifier = Modifier
        .testTag(TaskRowTag)
        .semantics { priority = task.priority }
    ) { /* … */ }
}

// test:
rule.onNode(hasTestTag(TaskRowTag) and SemanticsMatcher.expectValue(PriorityKey, 1))
    .assertIsDisplayed()

// "this row has a priority assigned at all":
rule.onNode(hasTestTag(TaskRowTag) and SemanticsMatcher.keyIsDefined(PriorityKey))
    .assertIsDisplayed()
Pattern: dropdown / IME-action / scroll-to-key — narrow a TextField query
kotlin
// "the editable TextField that handles Done as IME action"
rule.onNode(hasSetTextAction() and hasImeAction(ImeAction.Done))
    .performTextInput("hello")

// "any LazyColumn child reachable by key — i.e. has IndexForKey on top of ScrollToIndex"
rule.onNode(hasScrollToKeyAction()).performScrollToKey(itemKey)

hasScrollToKeyAction is the conjunction hasKey(ScrollToIndex) and hasKey(IndexForKey) (Filters.kt:415-416). hasScrollToNodeAction adds an axis-range check (Filters.kt:419-425).

Pattern: matcher description appears in error messages
kotlin
val matcher = hasText("Submit") and hasClickAction() and isEnabled()
println(matcher.description)
// (Text + InputText + EditableText contains 'Submit' (ignoreCase: false)) &&
// (OnClick is defined) && (is enabled)

The description is human-readable and used by assert(matcher) (Assertions.kt:254-267) when the matcher does not hold. Clauses MUST be readable in isolation — that is why named matchers are preferred over inline lambdas.

Mandatory rules

  • MUST use infix and / infix or / operator not to compose matchers; MUST NOT chain assertIs* calls when a single composed matcher captures the same intent.
  • MUST wrap custom semantics keys with SemanticsMatcher.expectValue(...) or SemanticsMatcher.keyIsDefined(...); MUST NOT access node.config[CustomKey] from inside an ad-hoc lambda. The factory methods produce readable error descriptions.
  • MUST prefer hasAnyAncestor(isDialog()) / hasAnyDescendant(...) over multi-step traversal when the relationship is "somewhere above/below". Cross-reference: ../traversing-the-semantics-tree/SKILL.md.
  • MUST keep the useUnmergedTree flag at its default false unless the matcher targets an inner element collapsed by merge. Skydoves hot take #2.
  • MUST NOT redefine an existing prebuilt matcher (e.g. writing a custom SemanticsMatcher("is enabled") { … }) — use isEnabled(). Custom matchers are reserved for keys that don't have a prebuilt filter.
  • PREFERRED: prefer tag-anchored matchers — hasTestTag(SubmitTag) and isEnabled() — over text-anchored. Skydoves hot take #1.

Verification

  • Every multi-condition query uses one onNode(matcher) rather than chained finders + assertions.
  • Custom key checks use SemanticsMatcher.expectValue / keyIsDefined — node.config[...] does not appear in matcher predicates.
  • ./gradlew :app:connectedDebugAndroidTest or :app:testDebugUnitTest passes.
  • Failure messages from intentionally-broken matchers print the composed description so the failing clause is identifiable.
  • No matcher is silently shadowed by a re-declared local lambda with the same name.

References

© skydoves, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in compose/finders/composing-semantics-matchers of skydoves/android-testing-skills.

Open the folder on GitHubat commit 8665ed5

Compare with similar skills

Composing Semantics Matchers next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Composing Semantics Matchers compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Composing Semantics Matchers this skillskydoves/android-testing-skills333—~3.2kAutomated safety check: PassApache-2.0
React Native Best Practicesvercel-labs/openreview1.7k17 repos~1.1kAutomated safety check: PassMIT
Swiftui Protwostraws/SwiftUI-Agent-Skill5.1k2 repos~1.5kAutomated safety check: PassMIT
Kortix Brandkortix-ai/suna20k—~4kAutomated safety check: PassCustom licence
Ip As LogoKartikLabhshetwar/better-shot2.4k1 repos~4.3kAutomated safety check: PassMIT
Compose Multiplatform Patternsmonta-app/ocpp-emulator1805 repos~2kAutomated safety check: PassApache-2.0

Similar skills

  • React Native Best Practices

    vercel-labs/openreview

    Official

    A prioritized rule set for React Native and Expo apps covering list performance, animation, navigation, UI patterns, state, rendering, monorepos and configuration.

    1.7k GitHub starsUsed in 17 repos~1.1k tokens
    MobileAuto-check passed
  • Swiftui Pro

    twostraws/SwiftUI-Agent-Skill

    Comprehensively reviews SwiftUI code for best practices on modern APIs, maintainability, and performance.

    5.1k GitHub starsUsed in 2 repos~1.5k tokens
    MobileAuto-check passed
  • Kortix Brand

    kortix-ai/suna

    Load FIRST for anything that carries the Kortix look or voice: product or mobile UI, copy of any kind, decks, social, images, email, CLI output, anything with the logo, and reviews of these.

    20k GitHub stars~4k tokensUpdated today
    MobileAuto-check passed
  • Ip As Logo

    KartikLabhshetwar/better-shot

    Generate extremely simple, cute, personified square character images with rounded heavy forms, two purposeful character colors, one solid background color, and a dominant lower-corner composition.

    2.4k GitHub starsUsed in 1 repo~4.3k tokens
    MobileAuto-check passed
  • Compose Multiplatform Patterns

    monta-app/ocpp-emulator

    Compose Multiplatform and Jetpack Compose patterns for KMP projects — state management, navigation, theming, performance, and platform-specific UI.

    180 GitHub starsUsed in 5 repos~2k tokens
    MobileAuto-check passed
  • Aso Appstore Screenshots

    adamlyttleapps/claude-skill-aso-appstore-screenshots

    Generate high-converting App Store screenshots by analyzing your app's codebase, discovering core benefits, and creating ASO-optimized screenshot images using Nano Banana Pro.

    1.8k GitHub starsUsed in 1 repo~9.6k tokens
    MobileAuto-check passed

More from skydoves/android-testing-skills

All 50 skills in this repo
  • Asserting Bounds And Dimensions

    skydoves/android-testing-skills

    A skill your agent uses to verify Compose layout measurements from a UI test using assertWidthIsEqualTo, assertHeightIsEqualTo, assertWidthIsAtLeast, assertHeightIsAtLeast…

    333 GitHub stars~3.3k tokensUpdated 4 mo ago
    Auto-check passed
  • Asserting Node State And Text

    skydoves/android-testing-skills

    A skill your agent uses to verify a Compose semantics node's properties from a UI test using assertExists, assertDoesNotExist, assertIsDisplayed, assertIsNotDisplayed, assertIsDeactivated…

    333 GitHub stars~3.6k tokensUpdated 4 mo ago
    Auto-check passed
  • Capturing Preview Screenshots In CI

    skydoves/android-testing-skills

    A skill your agent uses to render every Jetpack Compose @Preview as a screenshot on a real Android device or emulator and publish a browsable HTML catalog from CI.

    333 GitHub stars~4.5k tokensUpdated 4 mo ago
    Auto-check: notes
  • Capturing Screenshots And Screenrecord

    skydoves/android-testing-skills

    A skill your agent uses to capture visual artefacts from a device for test failures, golden image generation, QA repro, and demo videos.

    333 GitHub stars~3.7k tokensUpdated 4 mo ago
    Auto-check passed
  • Choosing Test Rule Vs Runtest

    skydoves/android-testing-skills

    A skill your agent uses to pick the correct Compose UI test entry point.

    333 GitHub stars~4.5k tokensUpdated 4 mo ago
    Auto-check passed
  • Choosing What To Test

    skydoves/android-testing-skills

    A skill your agent uses to pick which behaviors to cover in an Android test suite using Google's five-category state vocabulary plus the explicit "what NOT to test" list from…

    333 GitHub stars~4.6k tokensUpdated 4 mo ago
    Auto-check passed

Categories

Questions about Composing Semantics Matchers

What does Composing Semantics Matchers do?

A skill your agent uses to build precise Compose UI test queries by composing SemanticsMatcher predicates with infix and, infix or, and operator not, plus the prebuilt filter library (hasText…. Composing Semantics Matchers is an agent skill from skydoves/android-testing-skills. Use this skill to build precise Compose UI test queries by composing SemanticsMatcher predicates with infix and, infix or, and operator not, plus the prebuilt filter library (hasText, hasClickAction, isEnabled, isOn, hasTestTag, hasContentDescription, hasParent, hasAnyAncestor, hasAnyChild, hasAnySibling, hasAnyDescendant, hasImeAction, hasScrollToKeyAction, hasScrollToNodeAction, isDialog, isPopup, isRoot, isFocused, isEditable, isHeading).

When should I use Composing Semantics Matchers?

Composing Semantics Matchers fits situations like: build precise Compose UI test queries by composing SemanticsMatcher predicates with infix and; plus the prebuilt filter library (hasText; hasContentDescription; hasAnyDescendant.

How do I install Composing Semantics Matchers in Claude Code?

Run `npx skills add skydoves/android-testing-skills --skill composing-semantics-matchers -a claude-code`. Or copy the skill folder (compose/finders/composing-semantics-matchers in skydoves/android-testing-skills) into .claude/skills/composing-semantics-matchers in your project. Claude Code loads it when a task matches its description.

How do I install Composing Semantics Matchers in Codex?

Run `npx skills add skydoves/android-testing-skills --skill composing-semantics-matchers -a codex`. Or copy the skill folder (compose/finders/composing-semantics-matchers in skydoves/android-testing-skills) into .agents/skills/composing-semantics-matchers in your project. Codex loads it when a task matches its description.

Can I use Composing Semantics Matchers in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add skydoves/android-testing-skills --skill composing-semantics-matchers -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/composing-semantics-matchers, .gemini/skills/composing-semantics-matchers, .github/skills/composing-semantics-matchers and .opencode/skills/composing-semantics-matchers in your project.

What does Composing Semantics Matchers need to run?

SKILL.md names no scripts, command-line tools or credentials: Composing Semantics Matchers is instructions for the agent only.

Does Composing Semantics Matchers access the network?

SKILL.md names 1 domain. As links in the text: developer.android.com. This is read from the text; nothing was executed.

Is Composing Semantics Matchers safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Composing Semantics Matchers use?

Composing Semantics Matchers is published under the Apache-2.0 licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Composing Semantics Matchers use?

About 3.2k tokens (SKILL.md is roughly 13k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Composing Semantics Matchers?

Skills that share tags, products or a category with Composing Semantics Matchers: React Native Best Practices (vercel-labs/openreview, 1.7k stars), Swiftui Pro (twostraws/SwiftUI-Agent-Skill, 5.1k stars), Kortix Brand (kortix-ai/suna, 20k stars) and Ip As Logo (KartikLabhshetwar/better-shot, 2.4k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Composing Semantics Matchers?

skydoves (a GitHub user) maintains it in skydoves/android-testing-skills, which has 333 GitHub stars. The repository holds 50 skills in this directory. The repository was last updated on May 25, 2026.

Source: skydoves/android-testing-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.