A terminal-based manager for Android Virtual Devices and ADB-connected devices.
Wraps the Android SDK command-line tools (emulator, adb, avdmanager) in an
interactive TUI — no Android Studio required.
┌─────────────────────────────────────────────────────┐
│ avdm — Headless AVD Manager v0.1.0 │
├─────────────────────────────────────────────────────┤
│ │
│ > AVD Devices (manage virtual devices) │
│ Connected Devices (ADB-connected devices) │
│ Wireless Connect (connect via IP) │
│ Wireless Pairing (pair new device) │
│ Doctor (environment health check) │
│ Settings (SDK path, defaults) │
│ Quit │
│ │
├─────────────────────────────────────────────────────┤
│ ↑/↓ navigate ⏎ select q quit ? help │
└─────────────────────────────────────────────────────┘
| Feature | Status |
|---|---|
| List, start, and stop AVDs | Planned (Phase 1) |
| Real-time emulator log viewer | Planned (Phase 1) |
| List connected ADB devices | Planned (Phase 1) |
| Wireless ADB connect / disconnect | Planned (Phase 1) |
| Wireless ADB pairing (Android 11+) | Planned (Phase 1) |
Environment health check (doctor) |
Planned (Phase 1) |
| SDK path configuration | Planned (Phase 1) |
| Create / delete AVDs | Planned (Phase 2) |
| System image management | Planned (Phase 2) |
| Snapshot management | Planned (Phase 3) |
| Logcat viewer with filtering | Planned (Phase 3) |
- Go 1.22+ (for building from source)
- Android SDK with the following components installed:
platform-tools(providesadb)emulatorcmdline-tools(providesavdmanager,sdkmanager)
- macOS or Linux (Windows support is not planned)
The ANDROID_HOME environment variable should point to your SDK root, or the
SDK should be in a standard default location (see SDK Detection).
Run avdm doctor to verify your environment before first use.
Download the latest binary from the Releases page.
# macOS (Apple Silicon)
curl -L https://github.com/koechian/headless-avd-manager/releases/latest/download/avdm-darwin-arm64 -o avdm
chmod +x avdm && sudo mv avdm /usr/local/bin/git clone https://github.com/koechian/headless-avd-manager.git
cd headless-avd-manager
make build
# Binary is at ./bin/avdmmake installavdm # Launch the interactive TUI
avdm doctor # Run environment health checks (no TUI)
avdm version # Print version information
avdm help # Show help| Key | Action |
|---|---|
↑ / ↓ or k / j |
Navigate list |
Enter |
Select / confirm |
Esc |
Go back |
q |
Quit |
? |
Toggle help |
r |
Refresh current view |
s |
Start selected AVD |
x |
Stop selected AVD |
d |
Disconnect selected device |
avdm searches for the Android SDK in this order:
ANDROID_HOMEenvironment variableANDROID_SDK_ROOTenvironment variable (deprecated, but still checked)- Platform default paths:
- macOS:
~/Library/Android/sdk,~/Android/Sdk - Linux:
~/Android/Sdk,~/android-sdk,/opt/android-sdk
- macOS:
AVDs are read from ~/.android/avd/ (the standard location used by Android Studio).
avdm stores preferences in ~/.config/avdm/config.json:
{
"sdk_path": "",
"default_headless": false,
"default_gpu_mode": "auto",
"default_no_audio": false
}| Field | Default | Description |
|---|---|---|
sdk_path |
"" |
Override the auto-detected SDK root. Leave empty to use auto-detection. |
default_headless |
false |
Launch emulators without a window by default. |
default_gpu_mode |
"auto" |
GPU mode: auto, host, swiftshader_indirect, off. |
default_no_audio |
false |
Disable emulator audio by default. |
.
├── cmd/
│ └── avdm/
│ └── main.go # Entry point, CLI subcommand routing
├── internal/
│ ├── config/
│ │ └── config.go # Persistent JSON config (~/.config/avdm/)
│ ├── doctor/
│ │ ├── doctor.go # Orchestrates environment health checks
│ │ ├── checks.go # Individual check implementations
│ │ └── types.go # CheckResult, Report, Status types
│ ├── sdk/
│ │ ├── types.go # Shared types: AVD, Device, SDKPaths, etc.
│ │ ├── detect.go # Android SDK auto-detection
│ │ ├── adb.go # adb command wrappers
│ │ ├── emulator.go # emulator command wrappers
│ │ └── avdmanager.go # avdmanager command wrappers
│ ├── tui/
│ │ ├── app.go # Root Bubble Tea model, screen routing
│ │ ├── styles.go # Shared lipgloss styles and theme
│ │ ├── messages.go # Custom tea.Msg types
│ │ ├── keys.go # Key binding definitions
│ │ └── screens/
│ │ ├── menu.go # Main menu screen
│ │ ├── avdlist.go # AVD list + start/stop actions
│ │ ├── devicelist.go # Connected ADB devices list
│ │ ├── connect.go # Wireless connect form
│ │ ├── pair.go # Wireless pairing form
│ │ ├── logviewer.go # Real-time emulator/logcat output
│ │ ├── doctor.go # Doctor health check screen
│ │ └── settings.go # Settings screen
│ └── version/
│ └── version.go # Build-time version metadata
├── .github/
│ └── workflows/
│ ├── ci.yml # Lint + test on push/PR
│ └── release.yml # Cross-platform release builds on tag push
├── .gitignore
├── .golangci.yml # golangci-lint configuration
├── CHANGELOG.md # Keep a Changelog format
├── Makefile # Build, test, lint, release targets
├── go.mod
└── go.sum
# Install golangci-lint
brew install golangci-lint # macOS
# or: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latestmake build # Build the binary (./bin/avdm)
make test # Run all tests with race detector
make test-cover # Run tests and open HTML coverage report
make lint # Run golangci-lint
make fmt # Format all Go source files
make check # Full quality gate: vet + lint + test
make release # Cross-compile for macOS and Linux
make clean # Remove build artifactsgo test ./... # All tests
go test ./internal/sdk/... # Specific package
go test -run TestIsValidSDKRoot ./... # Single testThis project follows Conventional Commits:
feat: add wireless ADB pairing screen
fix: correct AVD status detection when emulator-5554 is offline
docs: add configuration reference to README
refactor: extract adb device parsing into separate function
test: add unit tests for doctor disk space check
chore: bump golangci-lint to v2.10.1
Commits should be atomic — one logical change per commit.
avdm uses Semantic Versioning:
- MAJOR — breaking changes to CLI interface or config format
- MINOR — new features, new doctor checks, new TUI screens
- PATCH — bug fixes, dependency updates, documentation
To create a release:
git tag -a v0.1.0 -m "chore: release v0.1.0"
git push origin v0.1.0
# The release GitHub Action builds and publishes binaries automatically.- Fork the repository
- Create a feature branch:
git checkout -b feat/my-feature - Make your changes with atomic commits
- Ensure all checks pass:
make check - Open a pull request against
main
Please update CHANGELOG.md under [Unreleased] with a summary of your changes.
MIT — see LICENSE for details.