Contributor guide¶
Welcome. Gloss is an open source Android app and contributions are very much welcome — whether that's a bug fix, a new feature, or just pointing out that a variable name is terrible. All of the above are valid pull requests.
What Gloss is¶
Gloss is an Android accessibility service that polishes your text without getting in your way. The flow is simple:
- You type something in any app — Gmail, Slack, Signal, a notes app, whatever.
- You pause for a moment.
- Gloss sends that text to your configured AI API and replaces it with a polished version, right in the same field.
- You carry on.
No switching apps. No copy-paste. No replacement keyboard. Your existing keyboard stays exactly as it is — Gloss works at the accessibility layer, above everything else.
The AI backend is your call: OpenRouter, a local
Ollama instance, or any service that speaks the
/chat/completions endpoint. If it's OpenAI-compatible, it works.
What it has¶
| Feature | What it does |
|---|---|
| Quick Settings tile | One-tap toggle directly from the notification shade. No need to dig through settings to turn Gloss on or off. |
| Overlay animation | A subtle visual indicator while your text is being processed. Reassurance that something is happening, not just silence. |
| Gloss level | A slider from 0 to 100. At the low end: grammar and punctuation fixes only. In the middle: light clarity edits. At the top: full rewrite. The model temperature adjusts automatically — 0.2 at the low end, 0.5 at the top. Pick your preferred level of interference. |
| History | Every successful gloss is stored locally — original text, result, which app it came from, token count, timestamp. Auto-pruned to the 200 most recent entries so it doesn't grow forever. |
| Encrypted API key | Your API key is stored in EncryptedSharedPreferences (AES256-GCM). It is never logged, never backed up, and never leaves the device in plaintext. |
| Neumorphic design | Soft shadows, depth, a considered palette. It looks like it belongs on Android rather than being a port of a website. |
| Full i18n | Localization support across the UI. |
Contributing¶
Before you start¶
Read the architecture overview in the repo — it maps the package structure and explains how the pieces connect. The code is well-commented, but the architecture doc saves you the archaeology.
Setup¶
You need:
- JDK 17 —
java -versionshould show 17.x - Android SDK API 36 — Android Studio bundles this; without Studio, use the command-line tools
- Gradle — comes via the wrapper, no manual install
git clone https://github.com/vladsolntsev/gloss.git
cd gloss
echo "sdk.dir=$HOME/Android/Sdk" > local.properties # adjust path if needed
./gradlew assembleDebug
No Android SDK at all? The repo has a Dockerfile that builds the debug APK in a
container. No local toolchain required.
The quality gate¶
CI runs ./gradlew check, which covers:
- Unit tests with JUnit 5 (plain JVM) and Robolectric (Android-dependent)
- 69% line coverage enforced via Kover — the build fails below this threshold
- ktlint 1.1.1 — code formatting
- detekt 1.23.8 — static analysis with project-level overrides in
detekt.yml
Run it locally before pushing:
Or the full local quality parity (includes docs lint):
If something fails, read the output — Gradle error messages are more helpful than they look at first glance.
Pull requests¶
- Fork the repo and work on a branch
- Keep commits focused; one logical change per commit is easier to review
- The PR description should explain why, not just what — the diff shows the what
- CI must be green before merge
Kotlin notes¶
Gloss is written in Kotlin 2.x. A few things worth knowing before you dive in:
Coroutines are used for async work — API calls, database operations. If you're new to coroutines, the official coroutines guide is genuinely good.
Sealed classes are used for error handling. GlossError is a sealed class with
branches like EmptyInput, MissingApiKey, HttpError, ParseError, NetworkError.
Pattern-match exhaustively and the compiler will tell you if you've missed a case.
It's one of the better parts of working in Kotlin.
Suppression — if you need to suppress a lint or detekt warning, do it locally with
@Suppress on the specific declaration, not as a blanket file-level disable. Known
suppressions are tracked in detekt_suppressions.txt.
detekt version — we're on 1.23.8 intentionally. The 2.0 alpha requires extra Android Gradle flags this project doesn't use, and there's no stable upgrade path yet. This will change when it does.
ktlint runs with android = true. If you use Android Studio, install the ktlint
plugin and let it format on save — you'll have fewer surprises at CI time.