Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,30 @@ and the project loosely follows [Semantic Versioning](https://semver.org/).

## [Unreleased]

### Added
- **No-account first run** — the model catalog now leads with a **Recommended**
section of ungated (Apache-2.0 / MIT) models that download with no Hugging Face
token; the app picks the best one that fits the device's RAM
(`recommendedModelId`). The license-gated **Gemma** tier moves behind a
collapsible **Advanced — Hugging Face account** section together with the token
field. This makes a fresh install (including a Play Store user with no HF
account) reach a working model in one tap.
- **First-run terms/source gate** — the final onboarding slide links the AGPL
source and Google's Gemma Terms, and clarifies that downloaded models carry
their own licenses.
- **Play Store readiness** — added [`PRIVACY.md`](PRIVACY.md) (hosted-ready,
zero-telemetry privacy policy) and [`PLAY_STORE.md`](PLAY_STORE.md) (a detailed
submission checklist: AAB, signing, Data Safety answers, permissions, content
rating, listing assets, compliance, and follow-ups). The policy is also served
as a static GitHub Pages site under [`docs/`](docs/), and **Settings → About →
Privacy policy** opens the hosted URL in-app.

### Changed
- **Cleartext traffic disabled** — `usesCleartextTraffic="false"` plus a
`network_security_config.xml` (`cleartextTrafficPermitted=false`). Model
downloads are HTTPS; local peer-to-peer sync uses raw sockets carrying
AES-GCM ciphertext and is unaffected.

## [0.8.0] — 2026-06-03

### Added
Expand Down
150 changes: 150 additions & 0 deletions PLAY_STORE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Publishing NativeLM to Google Play — readiness checklist

This is the end-to-end checklist for shipping the **NativeLM** sample app
(`com.nativelm.app`) to the Google Play Store. Items are grouped by whether they
are **done in the repo**, **done at build time**, or **done in the Play
Console**. Check each before your first production submission.

Legend: ✅ done in this repo · 🛠️ you do at build/release time · 🌐 you do in
the Play Console · ⏭️ recommended follow-up (not blocking).

---

## 1. Legal & compliance

- ✅ **Privacy policy authored & hosting prepared** — source in
[`PRIVACY.md`](PRIVACY.md); a static GitHub Pages site is committed under
[`docs/`](docs/) (`docs/index.html`, `docs/privacy/index.html`, `docs/.nojekyll`).
- 🌐 **Enable GitHub Pages (one-time, free for this public repo):** after this
merges to `main`, go to **Settings → Pages → Build and deployment**, set
**Source = "Deploy from a branch"**, **Branch = `main`**, **Folder = `/docs`**,
and Save. Pages is **free** for public repositories.
- 🌐 The privacy URL to paste into **Play Console → Policy → App content →
Privacy policy** will then be:
**`https://sagar-develop.github.io/litertlm-kmp/privacy/`**
- The site root (`https://sagar-develop.github.io/litertlm-kmp/`) is a small
landing page linking the policy and the source.
- ✅ **In-app terms/source disclosure** — the final onboarding slide links the
AGPL source and Google's Gemma Terms, and the gated-model download flow
reminds users to accept the model license on Hugging Face.
- 🌐 **AGPL-3.0 distribution.** As the sole copyright holder you may distribute
your own app on Play under Play's terms regardless of the AGPL (the AGPL binds
third parties, not you). Keep the source public (it is) so "Corresponding
Source" is available. If you ever accept outside AGPL contributions, require a
CLA to preserve this freedom and the dual-licensing model.
- 🌐 **Gemma / model licenses.** Gemma is under the
[Gemma Terms of Use](https://ai.google.dev/gemma/terms) and Prohibited Use
Policy, not an OSI license. The app downloads Gemma only when the user supplies
their own HF token and accepts the license on Hugging Face, so the user is the
licensee — but keep the in-app Gemma Terms link (done) and don't strip model
notices.

## 2. Data safety form (Play Console → App content → Data safety)

NativeLM collects/transmits **no** user data to us. Suggested answers:

- **Does your app collect or share any of the required user data types?** → **No.**
(No analytics, ads, crash SDKs, or backend. Conversations/documents stay
on-device; the only network is user-initiated model downloads sent directly to
the model host.)
- **Is all user data encrypted in transit?** → Not applicable to data *we*
collect (none). Model downloads use HTTPS; local P2P sync payloads are
AES-256-GCM encrypted.
- **Do you provide a way to request data deletion?** → Data never leaves the
device; users delete everything via **Settings → Clear all data** or uninstall.
- Declare the **microphone** usage truthfully: audio is processed on-device for
voice input and not sent off device.

> Re-check this form whenever you add a dependency — a new SDK can silently
> introduce data collection.

## 3. Permissions justification

The app declares only:

- `INTERNET`, `ACCESS_NETWORK_STATE` — model downloads.
- `RECORD_AUDIO` — on-device voice input (Whisper). Provide a prominent in-app
rationale before first mic use; declare on the Data Safety form.
- `CHANGE_WIFI_MULTICAST_STATE` — local peer-to-peer sync discovery (mDNS).

No `QUERY_ALL_PACKAGES`, no location, no broad storage. If Play flags any
permission, the justification above is the answer.

## 4. Build & signing

- 🛠️ **Build an Android App Bundle (AAB), not an APK** — Play requires AAB:
```
./gradlew :sample-app:bundleRelease
# output: sample-app/build/outputs/bundle/release/sample-app-release.aab
```
- 🛠️ **Release signing** is wired via `sample-app/keystore.properties`
(gitignored). Create it before a real release:
```properties
storeFile=/absolute/path/to/release.keystore
storePassword=…
keyAlias=…
keyPassword=…
```
Without it the release build falls back to debug signing (fine for local, **not**
for Play). Enroll in **Play App Signing**.
- ✅ **R8 minify + resource shrink** enabled on release; engine + native libs ship
consumer ProGuard rules.
- ✅ **64-bit only** (`arm64-v8a`) — meets Play's 64-bit requirement. (x86/emulator
not shipped; acceptable, but the Play pre-launch report's x86 devices will skip.)
- 🛠️ **Versioning** — bump `versionCode` for every upload (currently `6`) and set a
user-facing `versionName`.
- 🛠️ **`targetSdk`** must stay within Play's current window (one year of the latest
API). Verify before each submission.

## 5. Network / security

- ✅ **Cleartext disabled** — `usesCleartextTraffic="false"` +
`network_security_config.xml` (`cleartextTrafficPermitted=false`). Model
downloads are HTTPS; local P2P sync uses raw sockets carrying AES-GCM
ciphertext, unaffected by this policy.
- ✅ **`allowBackup="false"`** — no auto cloud backup of on-device data.

## 6. Store listing (Play Console)

- 🌐 App name, short & full description (lead with: private, on-device, no
account, no telemetry).
- 🌐 **Screenshots** — phone (and 7"/10" tablet if you target tablets); assets
exist under [`docs/screenshots/`](docs/screenshots/).
- 🌐 **App icon** (512×512) and **feature graphic** (1024×500). Adaptive launcher
icon is in the app.
- 🌐 **Content rating** questionnaire (IARC).
- 🌐 **Target audience & content** (not directed at children).
- 🌐 **Category**: Productivity / Tools.

## 7. Device experience & first run

- ✅ **No-account first run** — the catalog leads with **ungated** models
(Qwen3 0.6B, DeepSeek-R1 1.5B, Phi-4 mini, Qwen3 4B) that download with no HF
token; the app recommends the best one that fits the device's RAM. The gated
Gemma tier is behind the "Advanced" section. A reviewer or new user can reach a
working model with no Hugging Face account.
- ✅ **RAM-tier gating** — under-spec devices see "Not enough RAM" rather than an
OOM crash; downloads are SHA-validated and resumable.
- 🌐 Consider setting **device catalog / minimum RAM** expectations in the
listing so very low-RAM devices don't install and 1-star the app.
- 🌐 Run the **pre-launch report** and triage crashes on the low-end matrix.

## 8. Pre-submission testing

- 🛠️ Install and smoke-test the **release** AAB via a Play **internal testing**
track (not just `assembleDebug`) — R8 can change behavior.
- 🛠️ Verify: first-run downloads an ungated model with no token; gated download
shows the license reminder; voice input works; P2P sync works; "Clear all
data" wipes everything.

## 9. Recommended follow-ups (not blocking this release)

- ⏭️ **Foreground-service / WorkManager downloads.** Multi-GB model downloads
can be killed if the app is backgrounded mid-download. Wrap downloads in a
foreground service (with a notification) or WorkManager so they survive
backgrounding. Tracked separately from this PR.
- ⏭️ **Pin model revisions + SHA-256.** Catalog LLM URLs use Hugging Face
`resolve/main`, which can move; pin a revision and add `sha256` (as the Whisper
entry already does) for reproducible, tamper-evident downloads.
- ⏭️ **Wi-Fi-only download default** + clear data-usage messaging for large
models on metered connections.
108 changes: 108 additions & 0 deletions PRIVACY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# NativeLM — Privacy Policy

_Last updated: 2026-06-04_

NativeLM is a fully on-device AI app. It is built to do as much as possible
**without a network, without an account, and without sending your data anywhere.**
This policy explains exactly what that means.

> Plain-language summary: **We don't collect anything.** Your conversations,
> documents, and settings stay on your device. The app has no analytics, no
> ads, no account, and no backend server operated by us. The only network the
> app makes is downloading AI models you explicitly choose, directly from the
> model host (e.g. Hugging Face / Google).

## Who this applies to

This policy covers the **NativeLM** Android app (`com.nativelm.app`), published
as the reference application for the open-source
[litertlm-kmp](https://github.com/sagar-develop/litertlm-kmp) engine.

## What we collect

**Nothing.** NativeLM has no analytics SDK, no crash-reporting SDK, no
advertising SDK, and no telemetry. We, the developers, do not receive your
prompts, your model responses, your documents, your usage, your device
identifiers, or any diagnostics.

To make the zero-telemetry stance concrete, the app actively **removes** the
Google `datatransport` upload pipeline that the on-device OCR library (ML Kit)
would otherwise bundle, so it cannot initialize or upload anything. See the
`tools:node="remove"` entries in the app manifest.

## Data stored on your device

All of the following is stored **only on your device** and is never uploaded by us:

| Data | Where it lives | Notes |
|---|---|---|
| Conversations & messages | On-device database (ObjectBox) | Deletable per-conversation or via "Clear all data". |
| Projects, documents & vector index | On-device database + app file storage | Imported PDFs/text are processed locally for retrieval. |
| Studio artifacts | On-device database | Generated locally from your sources. |
| App settings (theme, language, app-lock, onboarding) | On-device preferences (DataStore) | — |
| Hugging Face token (optional) | Encrypted on-device (`EncryptedSharedPreferences`) | Only used to authenticate downloads of gated models. Never sent to us. |
| Downloaded model files | App file storage | Deletable from the Models screen. |

You can erase all of the above at any time from **Settings → Clear all data**,
or by uninstalling the app.

## Network access

The app makes network connections in only these cases, all initiated by you:

1. **Model downloads.** When you tap to download a model, the app connects
**directly to the model host** (e.g. `huggingface.co` / Google storage CDNs)
over HTTPS to fetch the file. For license-gated models (e.g. Gemma), your
Hugging Face token is sent **to Hugging Face only**, as the standard
`Authorization` header, to authorize that download. The app does not route
these downloads through any server we operate.
2. **Local peer-to-peer sync (optional).** If you use device-to-device sync,
your data is transferred **directly between your own devices over your local
Wi-Fi network** (no internet, no server). The transferred bundle is
end-to-end encrypted (AES-256-GCM) with a one-time code shown on the sending
device.

The app uses no cleartext HTTP for these connections, and declares
`cleartextTrafficPermitted="false"`.

When third parties (such as Hugging Face or Google) serve a model download to
you, their own privacy policies govern that interaction. We have no visibility
into it.

## Permissions and why they're used

- **Internet / network state** — to download models you choose.
- **Microphone (`RECORD_AUDIO`)** — only when you tap the mic for voice input.
Audio is transcribed **on-device** (Whisper) and is never uploaded; recorded
audio is used transiently for transcription and not retained as a file by us.
- **Wi-Fi multicast (`CHANGE_WIFI_MULTICAST_STATE`)** — only for discovering
your other device during local peer-to-peer sync.

The app requests no location, contacts, camera, or storage-wide permissions.

## Children's privacy

NativeLM is not directed at children and collects no personal information from
anyone, including children.

## Third-party / open-source components

NativeLM is open source under AGPL-3.0; the full source is at
<https://github.com/sagar-develop/litertlm-kmp>. AI models you download are
provided by third parties under their own licenses and terms (for example,
Google's [Gemma Terms of Use](https://ai.google.dev/gemma/terms)). You are
responsible for complying with the license of any model you download.

## Changes to this policy

If this policy changes, the updated version will be published at this URL with a
new "Last updated" date.

> Hosted copy: this policy is published via GitHub Pages at
> <https://sagar-develop.github.io/litertlm-kmp/privacy/> (the source of the
> hosted page is [`docs/privacy/index.html`](docs/privacy/index.html); this
> Markdown file is the canonical text).

## Contact

Questions about this policy: **sgupta8874@gmail.com**
Empty file added docs/.nojekyll
Empty file.
Loading
Loading