bundled-skills/earllm-build/SKILL.md
Build, maintain, and extend the EarLLM One Android project — a Kotlin/Compose app that connects Bluetooth earbuds to an LLM via voice pipeline.
npx skillsauth add FrancoStino/opencode-skills-antigravity earllm-buildInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Build, maintain, and extend the EarLLM One Android project — a Kotlin/Compose app that connects Bluetooth earbuds to an LLM via voice pipeline.
EarLLM One is a multi-module Android app (Kotlin + Jetpack Compose) that captures voice from Bluetooth earbuds, transcribes it, sends it to an LLM, and speaks the response back.
C:\Users\renat\earbudllm
app ──→ voice ──→ audio ──→ core-logging
│ │
├──→ bluetooth ──→ core-logging
└──→ llm ──→ core-logging
| Module | Purpose | Key Files |
|--------|---------|-----------|
| core-logging | Structured logging, performance tracking | EarLogger.kt, PerformanceTracker.kt |
| bluetooth | BT discovery, pairing, A2DP/HFP profiles | BluetoothController.kt, BluetoothState.kt, BluetoothPermissions.kt |
| audio | Audio routing (SCO/BLE), capture, headset buttons | AudioRouteController.kt, VoiceCaptureController.kt, HeadsetButtonController.kt |
| voice | STT (SpeechRecognizer + Vosk stub), TTS, pipeline | SpeechToTextController.kt, TextToSpeechController.kt, VoicePipeline.kt |
| llm | LLM interface, stub, OpenAI-compatible client | LlmClient.kt, StubLlmClient.kt, RealLlmClient.kt, SecureTokenStore.kt |
| app | UI, ViewModel, Service, Settings, all screens | MainViewModel.kt, EarLlmForegroundService.kt, 6 Compose screens |
| Device | Model | Key Details | |--------|-------|-------------| | Phone | Samsung Galaxy S24 Ultra | Android 14, One UI 6.1, Snapdragon 8 Gen 3 | | Earbuds | Xiaomi Redmi Buds 6 Pro | BT 5.3, A2DP/HFP/AVRCP, ANC, LDAC |
These are verified facts from official documentation and device testing. Treat them as ground truth when making decisions:
Bluetooth SCO is limited to 8kHz mono input on most devices. Some support 16kHz mSBC. BLE Audio (Android 12+, TYPE_BLE_HEADSET = 26) supports up to 32kHz stereo. Always prefer BLE Audio when available.
startBluetoothSco() is deprecated since Android 12 (API 31). Use AudioManager.setCommunicationDevice(AudioDeviceInfo) and clearCommunicationDevice() instead. The project already implements both paths in AudioRouteController.kt.
Samsung One UI 7/8 has a known HFP corruption bug where A2DP playback corrupts the SCO link. The app handles this with silence detection and automatic fallback to the phone's built-in mic.
Redmi Buds 6 Pro tap controls must be set to "Default" (Play/Pause) in the Xiaomi Earbuds companion app. If set to ANC or custom functions, events are handled internally by the earbuds and never reach Android.
Android 14+ requires FOREGROUND_SERVICE_MICROPHONE permission and foregroundServiceType="microphone" in the service declaration. RECORD_AUDIO must be granted before startForeground().
VOICE_COMMUNICATION audio source enables AEC (Acoustic Echo Cancellation), which is critical to prevent TTS audio output from feeding back into the STT microphone input. Never change this source without understanding the echo implications.
Never play TTS (A2DP) while simultaneously recording via SCO. The correct sequence is: stop playback → switch to HFP → record → switch to A2DP → play response.
Headset button tap
→ MediaSession (HeadsetButtonController)
→ TapAction.RECORD_TOGGLE
→ VoicePipeline.toggleRecording()
→ VoiceCaptureController captures PCM (16kHz mono)
→ stopRecording() returns ByteArray
→ SpeechToTextController.transcribe(pcmData)
→ LlmClient.chat(messages)
→ TextToSpeechController.speak(response)
→ Audio output via A2DP to earbuds
MutableStateFlow / StateFlowMainViewModel.kt if the feature needs UI integrationsrc/test/ directoryVoiceCaptureController.kt handles PCM recording at 16kHz monogetMinBufferSize().coerceAtLeast(4096)BluetoothController.kt manages discovery, pairing, profile proxiesLlmClient.kt defines the interface — keep it genericStubLlmClient.kt for offline testing (500ms simulated delay)RealLlmClient.kt uses OkHttp to call OpenAI-compatible APIsSecureTokenStore.kt (EncryptedSharedPreferences)After code changes, regenerate the ZIP:
## From Project Root
powershell -Command "Remove-Item 'EarLLM_One_v1.0.zip' -Force -ErrorAction SilentlyContinue; Compress-Archive -Path (Get-ChildItem -Exclude '*.zip','_zip_verify','.git') -DestinationPath 'EarLLM_One_v1.0.zip' -Force"
./gradlew test --stacktrace # Unit tests
./gradlew connectedAndroidTest # Instrumented tests (device required)
| Engine | Size | WER | Streaming | Best For | |--------|------|-----|-----------|----------| | Vosk small-en | 40 MB | ~10% | Yes | Real-time mobile | | Vosk lgraph | 128 MB | ~8% | Yes | Better accuracy | | Whisper tiny | 40 MB | ~10-12% | No (batch) | Post-utterance polish | | Android SpeechRecognizer | 0 MB | varies | Yes | Online, no extra deps |
tools
Authorized security assessment of LLM applications and AI agents: prompt injection, tool abuse, RAG exposure, memory poisoning, system-prompt extraction, and agent-compliance engineering per OWASP LLM/ASI Top 10.
development
Builds two parameterized UI modes—流光溢彩白 (iridescent white) and 五彩斑斓黑 (colorful black)—with OKLCH, WebGL/CSS fallback, vision gating, screenshot QA, and total/per-color intensity reports. Use when a UI request names either mode or needs measured color parameters.
tools
Delegate coding tasks to the Kimi Code CLI (`kimi`) only when the user explicitly requests it, while the orchestrator retains review and landing responsibility.
development
Front-end JavaScript reverse engineering: locate signature chains, analyze encrypted request parameters, sample runtime behavior, and reproduce logic locally in Node for evidence-based output.