SwiftSlate
System-wide AI text assistant for Android — powered by Gemini, Groq, and any OpenAI-compatible endpoint
Type a trigger like ?fix at the end of any text, in any app, and watch it get replaced — instantly.
[!NOTE] SwiftSlate works in most apps — WhatsApp, Gmail, Twitter/X, Messages, Notes, and more. No copy-pasting. No app switching. Just type and go. Some apps with custom input fields may not be supported (see limitations).
📋 Table of Contents
- Quick Demo
- Features
- Built-in Commands
- Text Replacer Commands
- Supported AI Providers
- Getting Started
- How It Works
- Custom Commands
- API Key Management
- Backup & Restore
- App Screens
- Screenshots
- Localization
- Privacy & Security
- Tech Stack
- Architecture
- Building from Source
- Contributing
- Sponsors
- Support the Project
- License
- Star History
⚡ Quick Demo
📝 You type → "i dont no whats hapening ?fix"
⏳ SwiftSlate → ◐ ◓ ◑ ◒ (processing...)
✅ Result → "I don't know what's happening."
📝 You type → "hey can u send me that file ?formal"
⏳ SwiftSlate → ◐ ◓ ◑ ◒ (processing...)
✅ Result → "Could you please share the file at your earliest convenience?"
📝 You type → "Hello, how are you? ?translate:es"
⏳ SwiftSlate → ◐ ◓ ◑ ◒ (processing...)
✅ Result → "Hola, ¿cómo estás?"
✨ Features
🌐 Works Almost EverywhereIntegrates at the system level via Android's Accessibility Service. Works in most apps — messaging, email, social media, notes, browsers, and more. Some apps with custom input fields may not be supported (see limitations). ⚡ Instant Inline ReplacementType, trigger, done. The AI response replaces your text directly in the same field — no copy-pasting, no app switching. A spinner ( 🔑 Multi-Key RotationAdd multiple API keys for automatic round-robin rotation. If one key hits a rate limit, SwiftSlate seamlessly switches to the next. 🌙 AMOLED Dark ThemePure black ( |
🤖 Multi-Provider AIShips with Google Gemini, Groq, or connect any OpenAI-compatible endpoint — cloud providers, or local LLMs like Ollama, LM Studio, and others running on your network. 🛠️ Two Command TypesAI commands send text to your provider for intelligent transformation. Text replacer commands run entirely offline for instant local text manipulation — no API key needed. 🔒 Encrypted Key StorageAPI keys are encrypted with AES-256-GCM using the Android Keystore. Your keys never leave your device unencrypted. 🌍 Localized in 7 LanguagesApp UI available in English, French, German, Spanish, Portuguese (BR), Hindi, and Simplified Chinese. |
🧩 Built-in Commands
SwiftSlate ships with 9 AI-powered commands plus dynamic translation — ready to use out of the box:
| Trigger | Action | Example |
|---|---|---|
?fix |
Fix grammar, spelling & punctuation | i dont no whats hapening → I don't know what's happening. |
?improve |
Improve clarity and readability | The thing is not working good → The feature isn't functioning properly. |
?shorten |
Shorten while keeping meaning | I wanted to let you know that I will not be able to attend the meeting tomorrow → I can't attend tomorrow's meeting. |
?expand |
Expand with more detail | Meeting postponed → The meeting has been postponed to a later date. We will share the updated schedule soon. |
?formal |
Rewrite in professional tone | hey can u send me that file → Could you please share the file at your earliest convenience? |
?casual |
Rewrite in friendly tone | Please confirm your attendance at the event → Hey, you coming to the event? Let me know! |
?emoji |
Add relevant emojis | I love this new feature → I love this new feature! 🎉❤️✨ |
?reply |
Generate a contextual reply | Do you want to grab lunch tomorrow? → Sure, I'd love to! What time works for you? |
?undo |
Restore text from before the last replacement | Reverts to your original text before AI modified it |
?translate:XX |
Translate to any language | Hello, how are you? ?translate:es → Hola, ¿cómo estás? |
🌍 Supported language codes for translation
Use any standard language code with ?translate:XX:
| Code | Language | Code | Language | Code | Language |
|---|---|---|---|---|---|
es |
Spanish | fr |
French | de |
German |
ja |
Japanese | ko |
Korean | zh |
Chinese |
hi |
Hindi | ar |
Arabic | pt |
Portuguese |
it |
Italian | ru |
Russian | nl |
Dutch |
tr |
Turkish | pl |
Polish | sv |
Swedish |
…and many more. Any ISO 639 language code works — the AI model handles it.
🛠️ Text Replacer Commands
Beyond AI, you can create text replacer commands that run entirely offline — no API key, no network, instant execution:
| Use Case | Trigger | Replacement | Result |
|---|---|---|---|
| Signatures | ?sig |
— John Doe, CEO |
Appends your signature |
| Canned responses | ?ty |
Thank you for reaching out! I'll get back to you shortly. |
Instant reply template |
| Snippets | ?addr |
123 Main St, Springfield, IL 62701 |
Quick address insertion |
| Shortcuts | ?email |
contact@example.com |
Fast email insertion |
[!TIP] Text replacer commands execute instantly with zero latency — no spinner, no network call. Create them in the Commands tab by selecting the "Text Replacer" type.
🤖 Supported AI Providers
| Provider | Models | Notes |
|---|---|---|
| Google Gemini (default) | gemini-2.5-flash-lite, gemini-3-flash-preview, gemini-3.1-flash-lite-preview |
Free tier available at aistudio.google.com |
| Groq | llama-3.3-70b-versatile, llama-3.1-8b-instant, openai/gpt-oss-120b, openai/gpt-oss-20b, meta-llama/llama-4-scout-17b-16e-instruct |
Free tier at console.groq.com |
| Custom (OpenAI-compatible) | Any model your endpoint supports | Works with Ollama, LM Studio, vLLM, any /v1/chat/completions endpoint |
[!TIP] For local LLMs, set the endpoint to your machine's local address (e.g.,
http://localhost:11434/v1for Ollama). HTTP is allowed forlocalhost,127.0.0.1, and10.0.2.2.
🚀 Getting Started
Prerequisites
| Requirement | Details |
|---|---|
| Android Device | Android 6.0+ (API 23 or higher) |
| API Key | Free Gemini key at aistudio.google.com, or a key from Groq / any OpenAI-compatible provider. Not required for text replacer commands. |
Installation
[!TIP] The APK is only ~1.2 MB — lightweight with zero external dependencies for networking or JSON.
1. Download the latest APK from the Releases page
2. Install the APK on your device (allow installation from unknown sources if prompted)
3. Open SwiftSlate and follow the setup below
Setup in 3 Steps
|
Step 1 🔑 Add API Key Open the Keys tab, enter your API key. It's validated before saving. Add multiple keys for rotation. |
Step 2 ♿ Enable Service On the Dashboard, tap "Enable" → find "SwiftSlate Assistant" in Accessibility Settings → toggle it on. |
Step 3 ✍️ Start Typing! Open any app, type your text, add a trigger like |
⚙️ How It Works
flowchart TD
A["📝 You type: 'Hello wrld, how r u ?fix'"] --> B{"🔍 Accessibility Service\ndetects trigger"}
B -- "Text Replacer" --> C["⚡ Instant local replacement\n(no network call)"]
B -- "AI Command" --> D["🔑 Selects next API key\n(round-robin)"]
D --> E["🤖 Sends text + prompt\nto AI provider"]
E --> F["⏳ Shows inline spinner\n◐ ◓ ◑ ◒"]
F --> G["✅ Replaces text in-place"]
C --> G
style A fill:#1a1a2e,stroke:#e94560,color:#fff
style B fill:#1a1a2e,stroke:#0f3460,color:#fff
style C fill:#1a1a2e,stroke:#00b894,color:#fff
style D fill:#1a1a2e,stroke:#0f3460,color:#fff
style E fill:#1a1a2e,stroke:#0f3460,color:#fff
style F fill:#1a1a2e,stroke:#e94560,color:#fff
style G fill:#16213e,stroke:#00b894,color:#fff
🔧 Technical deep-dive
- Event Listening — SwiftSlate registers an Accessibility Service that listens for
TYPE_VIEW_TEXT_CHANGEDevents across all apps (ignoring its own UI and password fields) - Fast Exit Optimization — For performance, it first checks if the last character of typed text matches any known trigger's last character before doing a full scan
- Longest Match — When a potential match is found, it searches for the longest matching trigger at the end of the text
- Command Routing — Text replacer commands execute immediately on-device. AI commands proceed to the API call path
- API Call — The text + prompt is sent to the configured AI provider using the next available key in the round-robin rotation
- Inline Spinner — While waiting for the AI response, a spinner animation (
◐ ◓ ◑ ◒) replaces the text to provide visual feedback - Watchdog Timer — A 120-second safety timer auto-cancels stuck processing jobs to prevent the service from becoming unresponsive
- Text Replacement — The response replaces the original text using
ACTION_SET_TEXT - Fallback Strategy — If
ACTION_SET_TEXTfails (some apps don't support it), SwiftSlate falls back to a clipboard-based select-all + paste approach - Post-Replace Verification — A delayed check ensures the IME didn't clobber the replacement, re-applying if needed
- Bounded Responses — API responses are capped at 1 MB to prevent memory issues from malformed responses
🎨 Custom Commands
Create, edit, and manage your own commands in the Commands tab.
Two Types of Custom Commands
| Type | How It Works | Needs API Key? | Latency |
|---|---|---|---|
| AI | Sends text to your AI provider with your custom prompt | Yes | ~1–3 seconds |
| Text Replacer | Replaces the trigger with a fixed string, entirely offline | No | Instant |
Example AI Command Ideas
| Trigger | Prompt | Use Case |
|---|---|---|
?eli5 |
Explain this like I'm five years old. |
Simplify complex topics |
?bullet |
Convert this text into bullet points. |
Quick formatting |
?headline |
Rewrite this as a catchy headline. |
Social media posts |
?code |
Convert this description into pseudocode. |
Developer shorthand |
?tldr |
Summarize this text in one sentence. |
Quick summaries |
[!TIP] Just describe the transformation you want — SwiftSlate's system instruction automatically ensures the AI returns only the transformed text without extra commentary.
🔑 API Key Management
SwiftSlate supports multiple API keys with intelligent rotation:
| Feature | Details |
|---|---|
| Round-Robin Rotation | Keys are used in turn to spread usage evenly across all configured keys |
| Rate-Limit Handling | If a key gets rate-limited (HTTP 429), SwiftSlate tracks the cooldown and skips it automatically |
| Invalid Key Detection | Keys returning 401/403 errors are marked invalid and excluded from rotation |
| Encrypted Storage | All keys encrypted with AES-256-GCM via Android Keystore before being saved locally |
| Live Validation | Keys are validated against the provider's API before being saved |
[!TIP] Adding 2–3 API keys from different accounts helps avoid rate limits during heavy use. On the free tier, all keys under the same account share a single quota — so rotation only helps with keys from separate accounts.
💾 Backup & Restore
Export and import your custom commands as JSON files — useful for migrating to a new device or sharing command sets.
- Export — Saves all custom commands to a
.jsonfile via Android's file picker - Import — Loads commands from a
.jsonfile (validates format, trigger prefix, and size limits before importing)
Find both options in the Settings tab under Backup & Restore.
[!NOTE] Imported commands must use the same trigger prefix currently configured in the app. API keys are not included in backups for security.
🖥️ App Screens
SwiftSlate has four screens accessible via the bottom navigation bar:
📊 Dashboard
|
🔑 Keys
|
📝 Commands
|
⚙️ Settings
|
📸 Screenshots
Dark Mode
![]() |
![]() |
![]() |
![]() |
Light Mode
![]() |
![]() |
![]() |
![]() |
🌍 Localization
SwiftSlate's UI is available in 7 languages:
| Language | Code |
|---|---|
| 🇺🇸 English | en |
| 🇫🇷 French | fr |
| 🇩🇪 German | de |
| 🇪🇸 Spanish | es |
| 🇧🇷 Portuguese (Brazil) | pt-rBR |
| 🇮🇳 Hindi | hi |
| 🇨🇳 Simplified Chinese | zh-rCN |
The app automatically uses your device's language. Contributions for additional translations are welcome!
🔒 Privacy & Security
[!NOTE] SwiftSlate is built with privacy as a core architectural principle, not an afterthought.
| Concern | How SwiftSlate Handles It | |
|---|---|---|
| 👁️ | Text Monitoring | Only processes text when a trigger command is detected at the end. All other typing is completely ignored. Password fields are always skipped. |
| 📡 | Data Transmission | Text is sent only to the configured AI provider (Google Gemini, Groq, or your custom endpoint). No other servers are ever contacted. Text replacer commands never leave your device. |
| 🔐 | Key Storage | API keys are encrypted with AES-256-GCM using the Android Keystore system. Encryption failures throw rather than falling back to plaintext. |
| 📊 | Analytics | None. Zero telemetry, zero tracking, zero crash reporting. |
| 📖 | Open Source | The entire codebase is open for inspection under the MIT License. |
| 🔑 | Permissions | Only requires the Accessibility Service permission — nothing else. |
| 💾 | Backups | API keys and settings are excluded from Android cloud backups and device transfers. |
🏗️ Tech Stack
| Language | Kotlin 2.1 |
| UI | Jetpack Compose · Material 3 |
| Async | Kotlin Coroutines |
| HTTP | HttpURLConnection (zero external dependencies) |
| JSON | org.json (Android built-in) |
| Storage | SharedPreferences (encrypted via Android Keystore) |
| Core Service | Android Accessibility Service |
| Build System | Gradle with Kotlin DSL |
| Java Target | JDK 17 |
| Min SDK | API 23 (Android 6.0) |
| Target SDK | API 36 |
Zero third-party dependencies for networking or JSON parsing — SwiftSlate uses only Android's built-in APIs.
🏛️ Architecture
com.musheer360.swiftslate/
├── service/
│ └── AssistantService.kt # Core accessibility service — event listening,
│ # trigger detection, text replacement, inline spinner
├── api/
│ ├── GeminiClient.kt # Google Gemini API client
│ ├── OpenAICompatibleClient.kt # Unified client for Groq + any OpenAI-compatible endpoint
│ └── ApiClientUtils.kt # Shared utilities — response parsing, error handling,
│ # structured output extraction, system prompt
├── manager/
│ ├── KeyManager.kt # AES-256-GCM encrypted key storage, round-robin rotation,
│ │ # rate-limit tracking, invalid key detection
│ └── CommandManager.kt # Command CRUD, trigger matching (longest-match),
│ # prefix migration, import/export
├── model/
│ ├── Command.kt # Command data class (AI or Text Replacer)
│ └── ProviderType.kt # Provider constants (gemini, groq, custom)
├── ui/
│ ├── DashboardScreen.kt # Service status, key count, quick-start guide
│ ├── KeysScreen.kt # API key management with live validation
│ ├── CommandsScreen.kt # Command list, add/edit/delete with collapsible form
│ ├── SettingsScreen.kt # Provider, model, prefix, backup/restore
│ ├── components/ # Reusable UI components (cards, text fields, dividers)
│ └── theme/Theme.kt # AMOLED dark + light Material 3 color schemes
├── MainActivity.kt # AnimatedContent tab navigation (4 tabs)
├── SwiftSlateViewModel.kt # Shared ViewModel exposing managers + prefs
└── SwiftSlateApp.kt # Application class — SharedPreferences pre-warming
🔨 Building from Source
Prerequisites
- Android Studio (latest stable)
- JDK 17+
- Android SDK with API level 36
Build
# Clone the repository
git clone https://github.com/Musheer360/SwiftSlate.git
cd SwiftSlate
# Build debug APK
./gradlew assembleDebug
# Output: app/build/outputs/apk/debug/app-debug.apk
Install on device
adb install app/build/outputs/apk/debug/app-debug.apk
📦 Signed release build
export KEYSTORE_FILE=/path/to/your/keystore.jks
export KEYSTORE_PASSWORD=your_keystore_password
export KEY_ALIAS=your_key_alias
export KEY_PASSWORD=your_key_password
./gradlew assembleRelease
⚠️ Known Limitations
- Some apps use custom input fields that don't support Android's standard text replacement APIs. SwiftSlate includes a clipboard-based fallback, but apps like WeChat and Chrome's address bar may still not work. Most standard text fields (messaging apps, email composers, notes, etc.) work fine.
- Some OEMs restrict accessibility services. Certain manufacturers (e.g., OnePlus, Xiaomi) may hide or block third-party accessibility services in their settings UI. If SwiftSlate doesn't appear in your accessibility settings, check for a "Downloaded apps" or "Installed services" section, or try searching for it.
🤝 Contributing
Contributions are welcome! Here's how to get involved:
# 1. Fork the repository, then:
git clone https://github.com/YOUR_USERNAME/SwiftSlate.git
cd SwiftSlate
# 2. Create a feature branch
git checkout -b feature/amazing-feature
# 3. Make your changes and commit
git commit -m "Add amazing feature"
# 4. Push and open a Pull Request
git push origin feature/amazing-feature
Ideas for Contributions
- 🧩 New built-in commands
- 🤖 Additional AI provider integrations
- 🎨 UI improvements and new themes
- 🌍 Translations for more languages
- 📖 Documentation improvements
💜 Sponsors
SwiftSlate is made possible by the generous support of its sponsors. Thank you!
![]() @lifearien |
Want to see your name here? Become a sponsor →
❤️ Support the Project
SwiftSlate is free, open source, and built in my spare time. If it's useful to you, consider supporting its development:
- ⭐ Star this repo — it helps others discover SwiftSlate
- 💖 Sponsor on GitHub — even a small contribution keeps the project going
📄 License
This project is licensed under the MIT License — see the LICENSE file for details.









