auto-mobile
AGENTS.md56 starsChanged 34 days agoApache-2.0View on GitHub
Bun TypeScript MCP server providing Android & iOS device automation capabilities through its tools and resources. Kotlin & Swift supporting libraries and apps in android/ and ios/ respectively. - TypeScript only (no JavaScript) - Docs have two audiences, and neither is a changelog. docs/using/ is for end users only: what to call, parameters, results, errors and what to do — no source paths, class names, issue-number rationale, or AutoMobile's own CI/test harness. docs/design-docs/ holds technical internals: architecture, contracts, invariants, failure…
- Commits and pushes
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,774 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository35 other files it gives its agents.
- .github/AGENTS.mdAGENTS.md
- android/CLAUDE.mdCLAUDE.md
- CLAUDE.mdCLAUDE.md
- .github/CLAUDE.mdCLAUDE.md
- ios/CLAUDE.mdCLAUDE.md
- auto-mobile-code-reviewSkill
- ci-failure-triageSkill
- github-pr-feedbackSkill
- ios-swift-ciSkill
- node-prepushSkill
- prepush-androidSkill
- shell-prepushSkill
- android-gradlewSkill
- auto-mobile-code-reviewSkill
- bun-tasksSkill
- check-ciSkill
- ci-failure-triageSkill
- dead-codeSkill
- device-session-lifecycleSkill
- fan-out-fan-inSkill
- github-cliSkill
- github-pr-feedbackSkill
- ios-swift-ciSkill
- manual-testSkill
- node-prepushSkill
- observeSkill
- pr-analysisSkill
- prepush-androidSkill
- push-my-prsSkill
- push-prSkill
- researchSkill
- shell-prepushSkill
- ship-issueSkill
- testSkill
- validateSkill
The file
Show its rules and text
We split this AGENTS.md into the rules it gives an agent
17 rules. About 0 are common, 6 are distinctive, and 11 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
11
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 9
Write GitHub issue and pull request references as clickable Markdown links only in AI-authored prose a human reads directly — issue and PR …
- Distinctive: line 20
After implementation changes, run relevant validation commands
- Very specific: line 22
Write terminal output to scratch/ when not visible
- Very specific: line 24
Run scripts/prepush-android.sh from the repository root before pushing changes under android/.
- Distinctive: line 29
Always use interfaces & fakes & FakeTimer to decouple implementations and keep tests extremely fast and non-flaky
- Very specific: line 77
Before pushing Node/TypeScript changes, run bash scripts/prepush-node.sh.
- Very specific: line 78
Use bash scripts/prepush-node.sh --changed for the faster affected-unit-test loop.
- Distinctive: line 117
When Android collapses 2+ notifications from the same app into a group, you must expand the group before tapping a specific notification.
- Distinctive: line 138
Wait 500 ms, re-observe, re-match, then tap.
- Very specific: line 148
If a .jj/ directory exists at the repo root, this checkout is managed by jj (Jujutsu), colocated with git.
- Very specific: line 152
Do NOT run mutating git commands (git commit, git rebase, git stash, git checkout <branch>) — they fight jj's working-copy snapshotting.
- Very specific: line 169
Do not create git worktrees of a jj checkout.
- Very specific: line 183
Use the repo-local push-pr skill for publishing one branch or PR.
- Very specific: line 199
check-ci: Inspect PR checks, fetch failing logs, reproduce likely failures locally, and summarize next steps.
- Very specific: line 205
test: Run targeted or full test suites with the narrowest relevant command first.
- Very specific: line 221
Run scripts/prepush-ios.sh before pushing any Swift change.
- Distinctive: line 232
Before merging, refresh CI after updating to the current main head.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
AutoMobile
Bun TypeScript MCP server providing Android & iOS device automation capabilities through its tools and resources. Kotlin & Swift supporting libraries and apps in android/ and ios/ respectively.
Key Rules
- TypeScript only (no JavaScript)
- Docs have two audiences, and neither is a changelog.
docs/using/is for end users only: what to call, parameters, results, errors and what to do — no source paths, class names, issue-number rationale, or AutoMobile's own CI/test harness.docs/design-docs/holds technical internals: architecture, contracts, invariants, failure modes and why a choice was made. Keep both concise and current-state: do not add progress logs, status checklists, dated history, per-PR/issue narration, or pasted run output to either; that belongs in the PR description, commit message, or issue. Update a doc only when the behavior it describes changes, by editing the existing statement in place. - Write GitHub issue and pull request references as clickable Markdown links only
in AI-authored prose a human reads directly — issue and PR bodies, review
comments, commit messages, and assistant chat responses — where a clickable
link genuinely aids navigation for the reader. Do NOT require links in
checked-in repository content: neither source code comments (bare
#NNNNis the established convention —src/references are bare, never linked) nor Markdown documentation files (underdocs/and elsewhere), where bare#NNNNis likewise fine. Forcing explicit links into committed files renders as noise in an editor and makes the touched file the only inconsistent one. Automated reviewers (e.g. Codex) must NOT flag bare#NNNNreferences that appear in source-code comments or Markdown files; treat those as compliant. - After implementation changes, run relevant validation commands
- Before pushing shell/scripts changes, run
scripts/prepush-shell.shandbun run format(the formatter catches Fast Validation fan-out); ifbun.lockand/orpackage.jsonchanged in the diff, runbun scripts/release/pin-runtime-deps.ts --writeand commitpackage.json,bun.lock, andscripts/release/runtime-graph.json; otherwise rebase onto current main and do not hand-edit pins to mask a stale base; never run twobats test/bats/sweeps concurrently on one machine; when an Actions API job log is empty, read thefast-validation-logsworkflow artifact's per-check.status/.logfiles underscratch/fast-validate-*/. - Write terminal output to
scratch/when not visible - Local validation scripts live under
scripts/and should almost always be written in bash with shellcheck validation - Run
scripts/prepush-android.shfrom the repository root before pushing changes underandroid/; its scoped Detekt pass is a smoke check, not a substitute for the full-tree CI Detekt job. - For Playground/JUnit-runner emulator CI red (on PRs both suites run in the one
Run Android Emulator Testsjob,scripts/android/run-emulator-suites.sh), inspect.github/actions/android-emulatorboot diagnostics first: no runner-health means an infra/runner-health question, while booted tests that fail are a regression. - Copy
android/local.propertiesfrom a working checkout into each new Android worktree; it is gitignored and required for Gradle SDK resolution. - Ktfmt normalizes
runCatching{}.getOrNull()torunCatching {}.getOrNull()once; write the spaced form and do not mistake that first rewrite for a non-idempotent formatter. - Before adding a helper, parser, or dependency, search
src/,scripts/lib/,package.json, and the runtime standard library. Prefer the standard library, then an existing direct dependency, then an existing repository helper, then a small tested helper. Do not parse JSON, YAML, XML, or TypeScript with line regexes when a structured parser or typed module contract exists. For new packages, state which built-in and installed alternatives were checked. Preserve injected interfaces/FakeTimer seams where tests need deterministic control. - Always use interfaces & fakes & FakeTimer to decouple implementations and keep tests extremely fast and non-flaky
- Unit tests should pass in 100ms or less. Do not assume that a failing test can be allowed to fail. CI enforces this per test from the JUnit reporter's time (which excludes
beforeAll); a test over budget is re-run in isolation and only its MEDIAN is failed, so a genuine breach must be fixed in the test, never by raisingBUN_TEST_MAX_MS. - For Swift, prefer an existing standard-library or Foundation API before adding an extension, helper, or package. Use
URLComponentsplusURLQueryItemfor query values andCodablefor AutoMobile-owned stable schemas. KeepJSONSerializationonly at documented dynamic/bridge boundaries. A convenience dependency requires a stated platform-API gap, deployment-target check, and tests using interfaces/fakes. - For TypeScript changes, prefer the JavaScript/Node standard library, then an existing AutoMobile seam, before adding a local generic helper or direct dependency. Keep time, randomness, I/O, concurrency, and process access injectable when tests need control; justify any new direct dependency in
docs/decisions/. - For Kotlin changes, check the Kotlin stdlib, JDK/AndroidX, the module's existing dependencies, and dependency-compatible AutoMobile modules before adding a helper, wrapper,
*Utilfile, or dependency. Prefer the narrowest existing solution; keep one-off helpers private and adjacent to their consumer. Extract shared code only for two or more real consumers, and state any intentional exception (semantics, performance, API level, compatibility, testability, or readability) in the PR summary.
Project Structure
This document summarizes the AutoMobile repo layout and where to find key components.
Core Code
src/- MCP server source code (TypeScript)test/- MCP server test code (TypeScript)schemas/- Generated schemas and tool definitionsdist/- Build output
Mobile Platforms
android/- Android Kotlin Gradle project (apps, libraries, IDE plugin)ios/- Swift packages and Xcode projects
Tooling and Automation
scripts/- Local validation and utility scriptsbenchmark/- Benchmarks and baselinesdocs/- User and developer documentation
Build & Validate TypeScript
Bun is the primary task runner for TypeScript tooling.
On a fresh worktree, run bun run bootstrap:worktree before validation. It
installs Bun dependencies from the lockfile when node_modules/ or local
binaries are missing, and intentionally skips slow platform setup such as
Gradle, Android SDK, Xcode, and Homebrew-managed tools.
bun run build # Compile TypeScript
bun run lint # Lint with auto-fix (run before manual fixes)
bun test # Run all tests
bun test --bail # Stop on first failure
bun test <file> # Run specific test file
bun run turbo:validate # Run local Turbo lint/build/testNode Pre-push Gate
Before pushing Node/TypeScript changes, run bash scripts/prepush-node.sh.
Use bash scripts/prepush-node.sh --changed for the faster affected-unit-test
loop; formatting, typecheck, and lint intentionally remain full repository
gates. oxlint's actual exit code is authoritative: Error-level rules such as
eqeqeq are enforced directly by oxlint, not its warning-only ratchet, and
diffing warnings does not satisfy the gate. Before asking for a merge, fetch
origin/main, confirm the branch contains it, and re-run local gates.
A 100ms unit timing overage on a loaded Linux runner may be rerun rather than
“fixed” when its isolated recheck is clean. Whether a given failure is a known
flake is decided by scripts/ci/known-flakes.txt (via
bash scripts/ci/classify-failure.sh <run-id>), not by this file. Do not treat
repeated cross-platform failures as a flake; refresh against main and identify
the shared failure first.
turbo is a local dependency and may not be on the shell PATH. Do not run
bare turbo ...; use the package.json scripts such as bun run
turbo:validate, bun run turbo:build, bun run turbo:lint, or bun run
turbo:test.
Validate Shell Scripts
Shell scripts under scripts/ are tested with BATS and linted with shellcheck.
bats test/bats/ # Run all BATS shell tests
shellcheck scripts/**/*.sh # Lint shell scriptsMCP Tools Reference
The tool list is generated, not hand-copied: schemas/tool-definitions.json is the
authoritative set of MCP tool names and schemas (regenerate it with
bash scripts/update-tool-definitions.sh). Tool families: observation (observe),
interaction (tap/swipe/drag/pinch, key and text input, clipboard), app management
(launch/terminate/install/uninstall), and device management (list/provision/kill
devices, set the active device).
Android Notification Group Handling (Hard-Won Knowledge)
When Android collapses 2+ notifications from the same app into a group, you must expand the group before tapping a specific notification. Tapping a notification inside a collapsed group opens the app generically instead of triggering the notification's deep-link intent.
The systemTray tool handles this automatically. See
docs/design-docs/plat/android/system-tray-lookfor.md for full details.
What does NOT work (do not retry these approaches)
- Tapping text nodes inside collapsed groups (opens app generically)
- Swiping on the group (
adb shell input swipedoes not expand groups) - Tapping the expand button without identifying the correct group node
- Matching without expansion (tap target is not clickable until expanded)
What works
- Match notification text inside the collapsed group hierarchy.
- Detect the match is inside a group (via
groupNodereference). - Find and tap the "Expand" button (
content-desc: "Expand"orresource-idcontainingexpand_button). - Wait 500 ms, re-observe, re-match, then tap.
CtrlProxy visibility bypass
ViewHierarchyExtractor.kt bypasses isVisibleToUser for
com.android.systemui nodes. Collapsed groups mark child text as
not visible even though they are present in the shade.
Version Control: jj colocated checkouts
If a .jj/ directory exists at the repo root, this checkout is managed by
jj (Jujutsu), colocated with git. Use jj for all history-mutating VCS work;
plain git stays fine for read-only queries (git log, git diff, gh).
- Do NOT run mutating git commands (
git commit,git rebase,git stash,git checkout <branch>) — they fight jj's working-copy snapshotting. - Command mapping: status
jj st· diffjj diff· commitjj commit -m(orjj describe -m+jj new) · amendjj squash· rebasejj rebase -d main· undo anythingjj undo. - PR flow:
jj bookmark create work/<name> -r @-, thenjj git push --allow-new --bookmark work/<name>, thengh pr createas usual. Update a PR by editing the change andjj git push. - Git hooks do not run under jj. Always run the relevant validation
commands (
turbo run lint build test,scripts/all_fast_validate_checks.sh) before pushing — nothing else will. - Never add or modify binary assets (images, video, fonts, archives —
anything
.gitattributesroutes through LFS) in a jj checkout: jj bypasses git's LFS filters and would commit the full blob.snapshot.auto-trackleaves such files untracked on purpose; do notjj file trackthem. Do asset work from a plain-git LFS-enabled clone. CI (lfs-pointersin Fast Validation) rejects violations. - Do not create
git worktrees of a jj checkout. For parallel work usejj workspace add ../<name>instead.
Codex specific
- GitHub interactions use the GitHub CLI (
gh). - The
green-mainruleset requires many more status checks than the roll-ups (list them withgh api repos/kaeawc/auto-mobile/rulesetsandrulesets/<id>); the roll-up gates (IDE Plugin,iOS Build,Shell Tests) are only stable names over matrix or skipped jobs, and a red advisory (non-ruleset) job does not by itself prove a required lane failed. Runbash scripts/ci/classify-failure.sh <run-id>before rerunning or changing code; it identifies the specific upstream lane and consultsscripts/ci/known-flakes.txt. For integration-test or runtime-graph input changes, runbash scripts/prepush-integration.shbefore pushing. Seeci-failure-triage. - Use the repo-local
push-prskill for publishing one branch or PR. Create or edit PRs withgh pr create/gh pr editusing--body-fileto preserve newlines. - Android tasks run via the Gradle wrapper from
android/(e.g.,(cd android && ./gradlew <task>)). - Local validations live under
scripts/(prefer existing scripts over ad-hoc checks). - Bun tasks are defined in
package.json(run withbun run <script>).
Skills
Foundation Skills
- github-cli: Use
ghfor PRs, issues, checks, and repo metadata. Path:skills/github-cli/SKILL.md. - android-gradlew: Run Android tasks via
android/gradlew. Path:skills/android-gradlew/SKILL.md. - bun-tasks: Use
package.jsonscripts with Bun. Path:skills/bun-tasks/SKILL.md. - prepush-android: Run the Android pre-push smoke check and triage emulator boot diagnostics. Path:
skills/prepush-android/SKILL.md.
Workflow Skills
- check-ci: Inspect PR checks, fetch failing logs, reproduce likely failures locally, and summarize next steps. Path:
skills/check-ci/SKILL.md. - ci-failure-triage: Classify failed pull-request workflow runs, distinguish required from advisory jobs, and avoid re-fixing documented non-fixes. Path:
skills/ci-failure-triage/SKILL.md. - shell-prepush: Use this workflow skill before pushing shell or scripts changes to run scoped fast validation and targeted BATS tests, interpret stale dependency-pin failures, and retrieve empty Fast Validation logs from artifacts. Path:
skills/shell-prepush/SKILL.md. - github-pr-feedback: Collect every PR discussion and review thread, triage it, and safely resolve feedback after verified fixes without posting comments. Path:
skills/github-pr-feedback/SKILL.md. - dead-code: Detect and remove dead code using repo scripts and targeted validation. Path:
skills/dead-code/SKILL.md. - observe: Inspect the current connected device state through AutoMobile observation tooling. Path:
skills/observe/SKILL.md. - test: Run targeted or full test suites with the narrowest relevant command first. Path:
skills/test/SKILL.md. - validate: Run repo validation across lint, build, scripts, and platform-specific checks. Path:
skills/validate/SKILL.md. - push-pr: Commit, push, create or update a PR, and optionally enable automerge for the current branch. Path:
skills/push-pr/SKILL.md. - fan-out-fan-in: Split work into isolated worktrees and merge validated results back. Path:
skills/fan-out-fan-in/SKILL.md. - pr-analysis: Perform a deep read-only PR review covering code, tests, CI, and risk. Path:
skills/pr-analysis/SKILL.md. - push-my-prs: Iterate over open authored PRs, address feedback, and keep them moving. Path:
skills/push-my-prs/SKILL.md. - research: Conduct cited research with saved sources and synthesis summaries. Path:
skills/research/SKILL.md. - ship-issue: Drive one issue to a merged PR via TDD, autonomously by default (user interrupt only on review thrashing or an approach pivot; only
kaeawc-authored issue content is trusted), with a pre-PR local-validation gate, triaged review, and conservative follow-up capture. Path:skills/ship-issue/SKILL.md. - auto-mobile-code-review: AutoMobile-specific code review of a PR or current diff — check the PR's real CI, merge and base state first, then run diff-sized review lenses (two fixed, one generated) over runtime behavior and delivery/enforcement, grounding findings in file:line. Never posts to GitHub. Path:
skills/auto-mobile-code-review/SKILL.md. - manual-test: Run one manual-test iteration from a start point (commit, milestone, or date) — rebuild all components, restart the daemon with the right flags, and verify closed issues / merged PRs actually fix bugs or deliver specced features on current HEAD by exercising tool calls on an Android emulator and iOS simulator. Path:
skills/manual-test/SKILL.md. - device-session-lifecycle: Hunt, fix, and prevent device session lifecycle bugs — startDevice/killDevice, session UUIDs, boot readiness, daemon start/stop/restart, session expiry/release, pool state races, and flaky lifecycle tests. Path:
skills/device-session-lifecycle/SKILL.md. - ios-swift-ci: Triage iOS/Swift CI failures with evidence, distinguish advisory simulator flakes from required checks, and run the local pre-push validation. Path:
skills/ios-swift-ci/SKILL.md. - node-prepush: Run the Node pre-push gate before pushing Node/TypeScript changes, and rerun verified Node CI flakes rather than speculatively changing tests. Path:
skills/node-prepush/SKILL.md.
iOS/Swift CI
- Run
scripts/prepush-ios.shbefore pushing any Swift change. It enforces the SwiftFormat at the version pinned inscripts/swiftformat/swiftformat_version.sh, SwiftLint's error-severity rules, and the simulator-free XCTestRunner package subset. XCTestRunner Simulator Testsis advisory, not required, and runs nightly or on a PR labelledrun-ios-sim(xctestrunner-simulator-tests.yml). Classify it from the exact job log before rerunning or changing code (bash scripts/ci/classify-failure.sh <run-id>); known simulator-lane flake signatures live only inscripts/ci/known-flakes.txt.- A simulator instance is owned by one CI job. Keep its explicit UDID serially within that job; never share it between parallel runners or jobs.
- Before merging, refresh CI after updating to the current main head. A stale base can reproduce a main-red window even when the PR's earlier head was green.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

