Best for
- Build new Compose-first screens and features for Android apps targeting API 28+
- Plan and execute bounded rewrites from Views or older Kotlin/Java codebases
- Set up agent-assisted Android workflows in Android Studio, Codex, or Claude Code
vasilyu1983/AI-Agents-public/frameworks/shared-skills/skills/software-android-native/SKILL.md
Guides native Android development with Kotlin, Jetpack Compose, and Views interop. Use when building, rewriting, or reviewing modern Android apps after establishing runtime truth.
Decision brief
Use this skill for native Android work only. It is the default shared-skill entrypoint for Compose-first Android apps targeting API 28+, bounded rewrites from older codebases, and agent-assisted workflows in Android Studio, Codex, and Claude Code.
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Declared | Source record | Install path and trigger |
| Claude Code | Declared | Source record | Install path and trigger |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/vasilyu1983/AI-Agents-public --skill "frameworks/shared-skills/skills/software-android-native"Inspect the Agent Skill "software-android-native" from https://github.com/vasilyu1983/AI-Agents-public/blob/53f6cb73ea53a2646e3e7d4665062ad66f3683ac/frameworks/shared-skills/skills/software-android-native/SKILL.md at commit 53f6cb73ea53a2646e3e7d4665062ad66f3683ac. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
1. Lock the baseline: existing app behavior, minimum API level, device classes, external integrations, and non-goals. 2. Choose the target defaults: Compose-first, API 28+, ViewModel + StateFlow, Hilt, Room + KSP, Kotlin Coroutines, JUnit 5, Compose Testing. 3. Slice the rewrite…
1. Start from data/sources.json for Google/Android docs and release notes. 2. Run a targeted web search for the specific Android Studio, Compose, or Kotlin question. 3. Prefer developer.android.com, kotlinlang.org, and official Android release notes.
Review the “Quick Reference” section in the pinned source before continuing.
Build new Compose-first screens and features for Android apps targeting API 28+
New native Android work: prefer Jetpack Compose for new screens and Views interop only where existing mature flows or third-party SDKs require it.
Permission review
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 96/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 82 | Source | Repository attention, not individual Skill quality |
| Compatibility | 2 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Use this skill for native Android work only. It is the default shared-skill entrypoint for Compose-first Android apps targeting API 28+, bounded rewrites from older codebases, and agent-assisted workflows in Android Studio, Codex, and Claude Code.
| Task | Default Picks | Notes |
|---|---|---|
| State & UI | ||
| New UI screens | Jetpack Compose | Views interop only where existing mature flows or third-party SDKs require it |
| Observable state | ViewModel + StateFlow (Kotlin 2.x) | Replaces LiveData for new code |
| Async work | Kotlin Coroutines + Flow | Dispatchers.IO for blocking, Dispatchers.Default for CPU; structured concurrency preferred |
| Unit/integration tests | JUnit 5 + Turbine | Turbine for Flow testing; JUnit 5 for coroutine lifecycle |
| UI tests | Compose Testing APIs (ComposeTestRule) | Espresso only for Views interop or legacy screens |
| State machine discipline | ||
| Submit guard | if (_uiState.value is Loading) return | Prevents double-tap duplicate submissions in ViewModel |
| Auto-reset transitions | viewModelScope.launch { delay(500); _uiState.value = Idle } | Input ready for next action without manual UI reset |
| Minimal sealed classes | Remove states that can't happen anymore | Dead sealed subclasses produce dead when branches and mislead future readers |
| Networking & resilience | ||
| Network reachability | ConnectivityManager + NetworkCallback wrapped in StateFlow | Publish isConnected; disable submit buttons when offline; observe in collectAsStateWithLifecycle |
| DI & architecture | ||
| Dependency injection | Hilt | @HiltViewModel, @Inject constructor, @Module + @InstallIn |
| Local persistence | Room + KSP | Prefer @Upsert over separate insert/update; KSP replaces KAPT |
| Background work | WorkManager + CoroutineWorker | Deferrable, constraint-aware background processing |
| Agent tooling & build | ||
| Agent tooling (in Android Studio) | Android Studio Gemini assistant | Built-in coding agent surface |
| Agent tooling (outside IDE) | Gradle CLI + ADB | Terminal-first build, install, launch, and inspection |
| Build command | ./gradlew assembleDebug | Or specific module: ./gradlew :app:assembleDebug |
| Install command | adb install -r app/build/outputs/apk/debug/app-debug.apk | -r replaces existing without clearing data |
| Launch command | adb shell am start -n com.example.app/.MainActivity | Verify package and component name from manifest |
| Emulator management | avdmanager, emulator CLI | Headless: emulator -avd Name -no-window -no-audio for CI |
| Logcat | adb logcat -s TAG:V | Filter by tag; adb logcat *:E for errors only |
| Screenshot | adb exec-out screencap -p > screenshot.png | Fast visual proof from emulator or device |
| Compose patterns | ||
| LazyColumn / LazyRow | Always provide key in items(key = { it.id }) | Prevents recomposition bugs on list mutation |
| Canvas drawing | Canvas(modifier) { drawScope -> ... } with DrawScope | Use drawLine, drawCircle, drawArc, drawPath |
| Canvas gestures | Modifier.pointerInput(Unit) { detectTapGestures / detectDragGestures } | Compute hit targets from coordinates, not invisible tap areas |
| Type-safe navigation | @Serializable route classes + NavHost (Navigation 2.9+) | Compile-time route safety; replaces string-based routes |
| Animations | animateFloatAsState, Animatable, InfiniteTransition | Choose based on one-shot vs continuous vs interruptible |
derivedStateOf | remember { derivedStateOf { ... } } | For computed state that depends on frequently changing sources |
| Side effects | LaunchedEffect, DisposableEffect, SideEffect | LaunchedEffect(key) for coroutine work; DisposableEffect for cleanup |
| Modifier order | Padding before background vs after changes result | Modifier chain is sequential; order is layout-significant |
Modifier.testTag | Modifier.testTag("submit_button") | Required for Compose test node finders |
| Snackbar | SnackbarHostState + SharedFlow from ViewModel | Collect events in LaunchedEffect; never use Toast for important feedback |
| Billing & payments | ||
| BillingClient | Play Billing Library 8+ (v9.x current as of 2026-07-11; v8+ mandatory for all new apps/updates by 2026-08-31, extension to 2026-11-01) | Initialize in Application.onCreate or Hilt singleton; verify current minimum at developer.android.com/google/play/billing/release-notes |
| Acknowledge purchases | acknowledgePurchase() within 3 days | Unacknowledged purchases auto-refund after 3 days |
| Subscription offers | ProductDetails.subscriptionOfferDetails | Base plan, offer phases (free trial, introductory price) |
| Promotional offers | Developer-determined offers in Play Console | Configure offer eligibility; apply via BillingFlowParams.SubscriptionUpdateParams |
| Consumables | consumeAsync() after backend confirms | Prevents re-granting; consume only after server receipt |
| Adaptive layouts | ||
| Window size classes | WindowSizeClass from material3-window-size-class | Compact, Medium, Expanded; branch layout in Composable |
| List-detail pane | ListDetailPaneScaffold (Material3 adaptive) | Canonical two-pane pattern for tablets and foldables |
| Navigation suite | NavigationSuiteScaffold | Auto-switches between bottom nav, rail, and drawer by size class |
| Foldable support | WindowInfoTracker (Jetpack Window) | Detect fold posture, hinge bounds; adapt layout for table-top mode |
| Auth & push | ||
| Credential Manager | CredentialManager API (Jetpack) | Unified passkeys, passwords, and federated sign-in |
| Biometric auth | BiometricPrompt (AndroidX) | canAuthenticate() check first; BIOMETRIC_STRONG for crypto |
| Push notifications | FCM (FirebaseMessaging) | onNewToken for registration; onMessageReceived for data messages |
| Notification channels | NotificationChannel (API 26+) | Must create before posting; group related channels with NotificationChannelGroup |
| Deep links | Compose Navigation deep links | navDeepLink { uriPattern = "app://..." } on route; App Links require assetlinks.json |
collectAsStateWithLifecycle | stateFlow.collectAsStateWithLifecycle() | Lifecycle-aware collection; prevents updates when app is backgrounded |
| Strong Skipping (Kotlin 2.x) | ||
| UI state instance identity | Split state into @Immutable slices; hoist derived lists to ViewModel | Strong Skipping Mode compares unstable params by reference; a fresh copy() per frame defeats skipping |
LazyListScope lambdas | val onClick = remember(id) { { vm.onClick(id) } } | Lambda memoization from Strong Skipping only applies inside @Composable — not inside items { } |
| Main-thread UI mutation | Do blocking work under withContext(Dispatchers.IO), assign _uiState.value = ... outside that block | Off-main state mutation surfaces as CalledFromWrongThreadException or ConcurrentModificationException in SnapshotStateObserver |
Use this skill to:
StateFlow and keep UI-facing state collected on the main thread with collectAsStateWithLifecycle.Dispatchers.IO for blocking I/O and Dispatchers.Default for CPU-bound work.build.gradle.kts) with version catalogs (libs.versions.toml).@Serializable route classes.Android native task
-> Confirm app shape: Compose, Views interop, service, or release gate
-> Prove Gradle, emulator/device, install, and launch reality
-> Choose architecture: ViewModel, StateFlow, Hilt, Room, Navigation
-> Implement bounded slice with lifecycle-aware state and tests
-> Check Kotlin, Compose, R8, billing, and Play-policy traps
-> Build, install, launch, inspect logs, and report proof
These are current headline footguns for Compose-first native Android on Kotlin 2.x. Each is source-backed; re-verify versions against the linked release notes before quoting a fix window.
CalledFromWrongThreadException / ConcurrentModificationException in SnapshotStateObserver. Compose reads snapshot state on the main thread; mutating _uiState.value from a coroutine body that ran on Dispatchers.IO without switching back surfaces as a main-thread crash or a reentrant-modification race. Fix: keep withContext(Dispatchers.IO) { ... } blocks pure (return a value, do not mutate state inside), assign _uiState.value = ... on the main dispatcher, and collect via collectAsStateWithLifecycle() — never a raw collect inside LaunchedEffect. See references/compose-state-concurrency.md.data class per event (_state.value = _state.value.copy(...)) defeats skipping even though the observable values are unchanged — LazyColumn rows recompose on every unrelated update. Fix: hoist derived lists and filtered views to the ViewModel with stateIn(scope, WhileSubscribed(5000), ...); split UI state into @Immutable slices; pass PersistentList<T> from kotlinx-collections-immutable. Source: developer.android.com/develop/ui/compose/performance/stability/strongskipping.LazyListScope lambda memoization gap. Strong Skipping's automatic lambda memoization applies inside @Composable functions; it does not apply inside LazyListScope.items { ... } or LazyColumn's content block. Unremembered callbacks captured there produce a new instance per recomposition. Fix: val onClick = remember(id) { { vm.onClick(id) } } at the items-block site, or hoist to a stable () -> Unit reference.kotlin("plugin.compose"). A stale or missing plugin declaration surfaces as Argument type mismatch: actual type 'Function0<Unit>', but '@Composable ComposableFunction0<Unit>' was expected — the transform did not run. Fix: lock plugin.compose to the exact Kotlin version in libs.versions.toml. Source: developer.android.com/jetpack/androidx/releases/compose-kotlin.LookaheadScope, nested Popup positioning against the screen instead of the parent, or a reentrant-modification crash in SnapshotStateObserver, upgrade to the latest Compose UI patch release before treating the problem as app-level — as of 2026-07-11 the production Compose BOM is in the 2026.06.xx line (Compose runtime/UI ~1.11.4, with 1.12 in beta requiring compileSdk 37 + AGP 9), and the SnapshotStateObserver reentrant-modification guard landed in the 1.10.0-rc01 cycle; a project still pinned below that line should treat this class of crash as a known-fixed upgrade target, not a fresh bug. Verify current at developer.android.com/jetpack/androidx/releases/compose-ui. Route to ../software-android-runtime-debugging/references/compose-debugging.md.kotlinx-serialization + R8 full mode. Since kotlinx-serialization 1.9.0, AGP 8.x release builds can fail with SerializationException: Serializer for class 'X' is not found or ExceptionInInitializerError, and the build emits warnings about <1>$* keep rules. Fix: keep the generated $serializer classes explicitly and run a release-variant smoke test in CI that exercises every @Serializable entry point. Route to ../software-android-runtime-debugging/references/proguard-r8-triage.md.These are behaviors to actively refuse in new code; they are not compile errors but each has caused measurable harm in production Kotlin/Android codebases.
| # | Anti-pattern | Why it bites | Better default |
|---|---|---|---|
| K1 | GlobalScope.launch { ... } | Marked @DelicateCoroutinesApi; JetBrains is phasing it out. Coroutines started here survive navigation, never cancel, and accumulate as memory leaks on busy screens. | viewModelScope, lifecycleScope, or an injected CoroutineScope parented to a SupervisorJob you own. |
| K2 | Passing an external Job into launch(externalJob) to "inherit" cancellation | Overrides the scope's job, becomes the parent, and breaks structured concurrency. Cancellation of the scope no longer propagates. Recent IntelliJ releases flag this with a coroutine inspection. | Never pass Job as a context argument. Use a child scope or a SupervisorJob explicitly scoped to the lifecycle you want. |
| K3 | LiveData + observeAsState in new Compose code | Hidden main-thread hop, older backpressure, worse interaction with Strong Skipping because State<T> produced by observeAsState wraps a mutable holder. | StateFlow + collectAsStateWithLifecycle() for new code. Keep LiveData only for legacy Views screens still on it. |
| K4 | Nullability as the primary way to model "loading" / "error" / "success" | Forces every call site to branch on null and loses type information about why the value is absent. | Sealed class / sealed interface: Idle / Loading / Success(data) / Error(message, cause) with an exhaustive when. Kotlin's compiler warns on missing branches when a new state is added. |
| K5 | Keeping kapt on Kotlin 2.x annotation processors | kapt uses the old JVM backend and is often incompatible with K2; slows every build and can silently drop generated code. | Migrate to KSP2 (K2-compatible). Hilt, Room, and Moshi-codegen all support KSP2; verify current support status in each library's release notes. |
| K6 | Treating StateFlow.value = copy(field = new) as free | Strong Skipping Mode compares the new object's reference to the old one. Even if only one primitive changed, consumers that take the whole state object as a parameter recompose. | Split state into logical slices, hoist derived lists, and prefer primitives or @Immutable sub-objects as composable parameters. |
| K7 | Filtering or sorting lists inside a composable body | Creates a new list reference per recomposition; Strong Skipping can never skip a downstream LazyColumn. | Compute in ViewModel, expose as StateFlow<ImmutableList<T>>; or wrap in derivedStateOf { ... } inside a remember. |
| K8 | runBlocking { ... } in production code paths (outside main() and tests) | Blocks the calling thread; on the main thread it freezes the UI and can ANR; in library code it defeats structured concurrency. | Make the function suspend and let the caller pick the scope. |
Route deeper pattern material through references/compose-state-concurrency.md.
Decisions that need a rationale, not just a default pick. As of 2026-07-11, verify each version-specific claim at the linked source before quoting it.
View-based render surface with no Compose wrapper (some map, ad, or video SDKs), (2) a legacy screen mid-migration where the cost of a full rewrite outweighs the interop tax, or (3) SurfaceView/TextureView-backed continuous rendering (camera preview, custom video) where Compose's AndroidView bridge is the right embedding, not a reason to avoid Compose for the rest of the screen. Do not accept "Views is faster" as a reason in 2026 — Compose's skip/restart model with Strong Skipping enabled is on par with or ahead of View-based RecyclerView diffing for list-heavy UI when state discipline (K6, K7) is followed.@HiltViewModel / WorkManager / Compose Navigation integration, and is what most enterprise Android codebases already standardize on. Prefer Koin instead only when: the team explicitly wants to avoid annotation processing and Gradle plugin overhead (KSP-free build), the project is small enough that compile-time graph validation matters less than iteration speed, or the codebase is a Kotlin Multiplatform module where Hilt cannot run (Hilt is Android/JVM-only; Koin runs on all KMP targets). Do not switch an existing Hilt codebase to Koin mid-project without a concrete, named pain point — DI framework churn has a high cost for a marginal ergonomics gain.commonMain artifacts. This is a real option for sharing business logic (networking, persistence, ViewModel state) across Android and iOS — but it is a product/architecture decision, not a default for this skill. If the task is "should we share code with iOS," route to software-mobile (or the software-mobile-architect advisor, where available) for the cross-platform tradeoff call before writing shared-module code; this skill assumes the Android-native side once that call is made. Verify current KMP/Compose Multiplatform stability status at kotlinlang.org/docs/multiplatform/supported-platforms.html.software-mobile-architect advisor) — do not let this skill's Compose-first defaults silently answer a platform-choice question it was not asked.suspend fun returns one value and is the wrong tool for anything that emits more than once (search-as-you-type, connectivity state, DB observation) — using a polling suspend loop instead of Flow produces stale reads and duplicate work. Conversely, wrapping a one-shot operation (a single network POST) in a Flow that a caller collects once adds Flow's cancellation/backpressure machinery for no benefit — a plain suspend fun is simpler and equally cancellable via structured concurrency. Rule of thumb: one value now -> suspend fun; zero-to-many values over time -> Flow; a single ViewModel-to-UI event stream that should not replay -> SharedFlow with replay = 0, not StateFlow.SavedStateHandle. ViewModel survives configuration change but not process death under memory pressure. Anything the user would be upset to lose on a background-kill-and-restore (form input mid-fill, scroll position, in-progress multi-step flow state) must go through SavedStateHandle (@HiltViewModel constructor-injects it automatically), not just ViewModel field state. Test this with adb shell am kill <package> while backgrounded, not just rotation — rotation alone never exercises the process-death path and gives false confidence.Use these thresholds when diagnosing jank or ANR reports; re-derive the math rather than quoting a remembered number.
Input dispatching timed out. This is the most common production ANR class and is almost always a synchronous DB/network/disk call on the main thread, not an actual 5-second-long computation.startForegroundService() must reach startForeground() within 5s or the system raises ForegroundServiceDidNotStartInTimeException territory (see S3 below for the related ForegroundServiceStartNotAllowedException/MissingForegroundServiceTypeException cases).onReceive() running past this window on the relevant app-state timer raises an ANR; move any real work off onReceive() into WorkManager or a coroutine launched from a longer-lived scope.onCreate()/onStartCommand()/onBind() blocking past this window raises an ANR; verify current thresholds at developer.android.com/topic/performance/anrs/diagnose-and-fix-anrs since these have shifted across Android versions.adb shell dumpsys gfxinfo <package> framestats or Android Studio's Frame Profiler on the actual refresh rate.Use a proof-first execution loop for native Android work:
Load references/runtime-proof-and-prompts.md for:
ComposeView in existing XML layouts as a bridge. Do not rewrite an entire Activity/Fragment hierarchy in one pass.Load references/ui-and-integration-patterns.md when the work involves:
Use a different skill when:
Recipes keyed to symptoms or migration moments. Each lists the shortest path to resolution using patterns above.
freeCompilerArgs += ["-P", "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=..."].unstable in the report; focus on those receiving the full UI state object.@Immutable slices and hoist derived lists to StateFlow in ViewModel.List<T> params with ImmutableList<T> from kotlinx-collections-immutable.skippable../gradlew :app:assembleRelease and trigger the failing serialization path.SerializationException: Serializer for class 'X' is not found.@Serializable class and its generated $serializer companion; see references/android-release-and-compliance.md.adb install -r and re-run the failing path end-to-end.ForegroundServiceStartNotAllowedException or MissingForegroundServiceTypeException.android:foregroundServiceType in the <service> manifest element (e.g. dataSync, mediaPlayback).ServiceInfo.FOREGROUND_SERVICE_TYPE_* flag to startForeground().adb shell am kill to simulate background-state entry before the start call.android:enableOnBackInvokedCallback="true" in the manifest <application> element.onBackPressed() overrides with OnBackPressedCallback registered on onBackPressedDispatcher.NavHost handles OnBackPressedCallback automatically; add explicit callbacks only for custom back logic.KeyEvent.KEYCODE_BACK handlers that now conflict with the new callback.BillingClient as a Hilt singleton; connect in Application.onCreate.BillingClient.BillingResponseCode.OK after purchase, call the backend to verify the purchase token server-side before granting access.acknowledgePurchase() within 3 days; unacknowledged purchases auto-refund.PurchasesUpdatedListener and queryPurchasesAsync(QueryPurchasesParams) on app foreground to catch out-of-band purchases.ITEM_ALREADY_OWNED gracefully by querying existing entitlements rather than surfacing an error.| Resource | Purpose |
|---|---|
| references/android-rewrite-playbook.md | Rewrite slicing, acceptance criteria, and evidence rules |
| references/agentic-android-tooling.md | Android Studio Gemini, Gradle CLI + ADB, and emulator selection rules |
| references/android-studio-workflows.md | Gradle wrapper, build variants, canonical build/test/install loops |
| references/codex-claude-android-workflows.md | Repo memory, approval boundaries, and prompt patterns |
| references/runtime-proof-and-prompts.md | Proof-first runtime execution, token discipline, and prompt shape |
| references/ui-and-integration-patterns.md | Compose, adaptive-layout, backend integration, and billing patterns |
| references/compose-state-concurrency.md | Verified app-layer defaults for Compose, StateFlow, and coroutines |
| references/android-release-and-compliance.md | Target SDK, data safety, ProGuard/R8, and release-gate checks |
| data/sources.json | Primary sources and current external references |
Use the rewrite brief at project start, the feature request per slice, the proof checklist at each verification gate, and the agent handoff at batch boundaries.
| Template | Purpose |
|---|---|
| assets/template-android-rewrite-brief.md | Rewrite scope and constraint brief |
| assets/template-android-feature-request.md | Feature-level Codex / Claude Code request format |
| assets/template-android-proof-checklist.md | Source-backed proof and validation checklist |
| assets/template-android-agent-handoff.md | Post-change handoff with evidence and residual risk |
| Skill | Purpose |
|---|---|
| software-mobile | Platform choice and cross-platform tradeoffs |
| qa-testing-android | Android test execution, device matrix, and Espresso/UI Automator |
| qa-testing-mobile | Cross-platform mobile QA strategy |
| agents-memory | Shared AGENTS.md / CLAUDE.md memory strategy |
| dev-context-engineering | Cross-tool context design for Codex and Claude Code |
| software-performance | Performance measurement and regression gates |
| software-baas-platforms | Backend platform selection and comparison |
| ai-context-layer/references/conversational-surfaces-cross-platform.md | Natural-conversation composition for Android (Gemini Nano via AICore / ML Kit GenAI, ObjectBox on-device vector index, deterministic Composer B for non-AICore devices) inside the cross-platform recipe |
Before applying this skill on a non-trivial task, read learnings.consolidated.md in this directory (and learnings.md if present).
After applying it, if you encountered a pattern worth remembering, a mistake worth preventing, or a domain fact that surprised you, append one dated bullet to learnings.md via agents-skills-feedback-loop/scripts/append_learning.py. Do not modify SKILL.md itself.
Frequently asked questions
Use this skill for native Android work only. It is the default shared-skill entrypoint for Compose-first Android apps targeting API 28+, bounded rewrites from older codebases, and agent-assisted workflows in Android Studio, Codex, and Claude Code.
The source record exposes this install command: npx skills add https://github.com/vasilyu1983/AI-Agents-public --skill "frameworks/shared-skills/skills/software-android-native". Inspect the command and pinned source before running it.
The pinned source record declares support for: codex, claude code.
Alternatives
PramodDutta/qaskills
Optimize resumes for Applicant Tracking Systems, check ATS compatibility, and analyze keyword match
vasilyu1983/AI-Agents-public
Configures Claude Code hooks and Codex hooks.json/notify callbacks. Use when adding guardrails, preflight, audit trails, worktree automation, or budget enforcement.
vasilyu1983/AI-Agents-public
Guides iOS testing with XCTest, XCUITest, Swift Testing, simctl, and xcresult. Use when choosing destinations, controlling flakes, or parsing test artifacts for native apps.
samber/cc-skills-golang
Monadic types for Golang using samber/mo — Option, Result, Either, Future, IO, Task, and State types for type-safe nullable values, error handling, and functional composition with pipeline sub-packages. Apply when using or adopting samber/mo, when the codebase imports `github.com/samber/mo`, or when considering functional programming patterns as a safety design for Golang.