Native Android app · alpha

Sideload the native Android app.

The Android app runs the same typed interview as the web app, natively. It is an early alpha with no Play Store listing: you install an APK with adb, either the signed release APK once releases carry one, or a debug build.

Hands-free voice is new, and has not been tried on a phone. Emulator checks do not establish physical-phone behavior; the declaration recording below distinguishes its real native effects from test setup. If you rely on voice on a phone today, the web app is the tested one; see Mobile and voice.

What is there, and what is not yet

Area Status
Navigation Ideas, New idea and Settings use bottom navigation in a compact window and a labelled side rail at medium or expanded widths. Interview and Result keep a contextual title and Back button; a long title can shorten visually while its complete text remains accessible. In a short Interview with the keyboard open, that bar scrolls with the content to leave room for the answer editor. History and persistent errors also count towards the short-window scroll decision, so they cannot leave a zero-height current-question area. The focused voice stage hides unrelated navigation until Exit.
Setup Two-step onboarding: choose a hosted or local provider, then add a key or find a model on your server. Read the named interview-text disclosure and affirm its unchecked agreement before saving and continuing.
Interview The current question and expanding answer box lead. Show earlier reveals the counted conversation; Coverage details shows factual dimension levels. Suggestions stay editable, the wrap offer has distinct actions, and the built-in checklist takes over when the model fails. Manual errors remain until Dismiss. An interrupted turn resumes.
Result A selectable rendered document with a bounded reading width and question/coverage/checklist metadata. Compact windows make Share .md primary with Copy markdown visible; expanded windows make Copy primary with Save .md visible. Share, Save and Ask me more remain reachable secondary actions, not four squeezed full-size labels.
Library Compact rows show status, coverage and updated date. Tap a row to Continue or View result on a phone; wide screens select a side-by-side detail instead. More offers View details, Rename or tag, Archive/Restore and Delete. Search stays visible; Filters holds tags and archived ideas.
Settings Connection, Voice, Appearance, Your data (backup and import) and About. Appearance offers System, Light and Dark; the saved choice applies before the app first renders. Android 12 and later use the system’s wallpaper colours; other devices use the built-in neutral/petrol light and dark palette. The app keeps Android’s system font.
Launcher icon The anvil adapts to your launcher’s icon shape. On Android 13 and later, enable Themed icons in your launcher’s wallpaper or home-screen settings to use its wallpaper colours instead of the brand background. Themed icons depend on launcher support; the app’s Appearance setting does not turn them on.
Manual dictation In a typed interview, tap Start dictation, speak, then tap Stop dictation. Recognised words are added to your editable answer draft; review them and tap Send yourself. Finish words and phrases such as “skip this one” remain literal text here. This is tap-to-start/tap-to-stop, not press-and-hold or automatic submission. Only microphone permission is needed; no notification or background service starts. Leaving the screen, editing, opening Report or starting hands-free cancels unfinished dictation and keeps the existing draft. Denial, no speech and input failures are reported beside the draft, without erasing it.
Hands-free input Hands-free interview on the interview screen asks for the microphone (and, on Android 13 and later, notifications), then reads each question aloud and listens until you say your finish word from Voice. A notification with Pause and Exit keeps the interview hearing with the screen off. Pause keeps the words captured so far as your draft; Exit returns to typing without writing anything up. If the microphone is refused, voice stands down and starts neither recognition nor its microphone service. Open app permission settings offers recovery; return and tap Resume deliberately, or Exit to keep typing. Notification permission is explained separately and is optional: refusing it does not block voice, and the stage says the controls remain here. The phone’s speech service processes audio, on-device where available; IdeaForge does not store audio.
Spoken replies In a voice interview only: the phone’s own voice reads each question, then its suggestions, at the speaking pace from Voice. In Settings → Voice → Device voice choice, choose Engine default or an installed name and locale. The saved choice applies to subsequent device speech, including fallback from OpenAI. Local/network labels are engine metadata, not a quality ranking or an offline guarantee. Opening Settings and choosing a voice never play a preview or request the microphone. Optional OpenAI speech (Marin or Cedar) is in Settings under Voice: it needs its own OpenAI key (never your interview key), three consents (an AI-generated voice, the spoken text sent to OpenAI, metered use) and a Check and preview that plays OpenAI audio on the phone. Changing the key or the voice, unticking a consent or Forget turns it off until the next passing check; unticking a consent or Forget also stops anything being spoken and pauses a voice interview. If OpenAI fails during an interview, the phone’s voice takes over and the voice stage says so. Last spoken identifies the backend that actually completed the last output, not a promise about the next one; Pause never switches voices.
Transcription fallback Only for phones whose speech recogniser is missing, or reports that it cannot recognise your language; the next voice interview tries the recogniser again. In Settings, choose Groq Whisper or OpenAI, paste a key for that service alone and agree to send recorded audio. Hands-free answers are then recorded (at most 45 seconds per segment and 120 seconds per answer) and transcribed. While the recogniser is working, nothing is recorded or sent. Manual dictation uses the same eligibility and its own current grant: Stop releases the microphone before one transcription, with the existing 120-second recording and upload-size bounds. Silence does not submit a manual answer, and transcribed commands remain ordinary draft text. Unticking the consent or Forget stops the next upload and pauses the interview; Pause keeps what was already transcribed as your draft. Transcribing is shown only while an actual upload is pending, and completed segments appear as captions.
Signed release Signed APKs are attached to GitHub releases, starting with the first tag after the release key’s fingerprint is published in SECURITY.md and the privacy contact is confirmed. While SECURITY.md still says PENDING, no signed APK exists; use the debug build below.

The focused voice screen keeps the idea, current question and full live or retained words together. Phase status is polite; microphone samples do not trigger repeated announcements or a fabricated meter. Pause/Resume and Exit remain separate large actions while long or enlarged text scrolls. Finish word and voice commands explains the configured finish word and commands that must occupy the whole utterance. Scripted emulator phase screenshots are layout evidence, not physical-phone voice or permission validation.

Automated tests run on the JVM; no physical-phone result is recorded in the repository yet.

Ideas distinguishes loading, an empty library, no filter matches and unavailable storage. If the library cannot be read, use Try again; it retries without deleting unreadable or newer files. Enlarged interview text and actions wrap or scroll rather than hiding Write it up. Resizing or rotating keeps the open idea and its draft; Ask me more reopens that same idea rather than creating another. Wide forms and documents keep bounded reading widths. Navigation alone never asks for the microphone.

Result keeps one logical vertical document scroll. Headings, lists and quotes reflow; wide code and tables scroll locally without changing the markdown exported by Share, Copy or Save. Failed synthesis and checklist provenance remain explicit while the transcript, open questions and coverage are preserved. Action failures stay visible until dismissed; a failed library read offers a retry rather than claiming the idea was deleted. Picker or share cancellation is not a success message, and Ask me more still reopens the same idea.

Connection setup keeps its two steps: choose a provider, then complete its required key or local-server fields. Back, Change and resizing retain this setup’s unsaved fields in memory. Saved settings, a previous successful check and a current failure are distinct; a saved key is not a live connection verdict. Wider windows show provider/privacy support beside a bounded form, while enlarged text falls back to one scrollable column.

After setup, or from New idea, choose Start with voice or Type instead. Opening, rotating or cancelling that choice does not create an idea or request the microphone. Only a deliberate mode selection opens one fresh interview. Cancelling the choice or leaving an untouched Type instead entry adds no empty item to Ideas; this is not a guarantee about exiting an already-started voice run. The new-idea Voice choice hands its intent to the visible Interview once. Cancelling or denying its microphone setup leaves the same usable typed screen with an explanation. Pending setup interrupted by navigation, backgrounding or recreation is not replayed automatically; retry voice explicitly or keep typing.

In Ideas, Clear filters recovers a search with no matches; Show archived finds ideas that were archived rather than deleted. More → View details previews an idea without opening the interview. An active idea without a write-up shows No write-up yet, its conversation and any unsent draft, not a generation error. Rename/tag and Delete have separate dialogs: Cancel or Back keeps the idea unchanged. Delete is permanent; Archive can be reversed. Backup and import remain in Settings under Your data.

Settings keeps all five sections in one scrolling form. Expanded windows add a narrow section index; large fonts fall back to one column when the index and form cannot both fit. Summaries identify the saved provider, permitted speech backend, current theme and library state, not a generic connected verdict. Index navigation preserves unsaved fields. Speech and transcription report their own outcomes; a failed check stays an error beside its action, not a successful toast.

Voice keeps the hands-free finish word, speaking pace and device voice choice. The old global Hands-free switch is gone: choose Voice or Type for a new idea, or use the explicit dictation and hands-free actions in Interview. Changing the finish word never turns manual dictation into a command listener.

Device voice choice keeps the saved identifier while the engine loads or fails. Use Reload device voices to retry, including after installing voices in the system text-to-speech settings. An empty list is reported explicitly. If the saved voice disappears, it is kept and a warning explains that subsequent device speech uses the engine default and reports the fallback. Choose another voice or Engine default deliberately to replace it. This setting does not change the separate OpenAI voice, key, successful check or consents.

Your data separates Backup ideas / Import ideas from Forget all keys. Forget asks explicitly and revokes before pending writes can restore credentials; ideas and ordinary device preferences stay. Cancel or Back changes nothing and returns focus to its action. Connection and speech operations keep their independent grants.

Connection also holds the inference agreement. Existing installations without it review and save it there before New idea, resumed model work or voice can start. Checking a key never ticks the box. Uncheck to withdraw immediately; save a fresh affirmative choice to enable interview work again. Switching provider kind, including switching back, or a validated local server address requires fresh agreement; model-only changes do not. Local ideas remain readable and exportable. Microphone, hosted transcription and hosted speech permissions stay separate. See the privacy policy for requests already sent and failed preference writes.

Privacy policy is in Settings → About and the footer of both onboarding steps, so you can read it before setting up a provider. It opens the published policy outside the app. If no browser can open it, the inline error and address are brought into view and you can try again; reading the policy does not check a provider.

Report AI output without sending it automatically

Report is beside generated questions and suggestion groups, including earlier conversation and Ideas previews, and in the Result actions. The voice stage also offers it for its question and suggestions; opening a report pauses hands-free voice or cancels manual dictation before the note can be entered, and never resumes the microphone automatically. Generated questions and suggestions are labelled; a mixed document says it contains AI-generated content. The opening question, a checklist replacement and missing synthesis are not labelled as generated.

  1. Tap Report, choose Offensive, Harmful, Inaccurate or Other, and optionally add a note. Review included generated text shows the exact snapshot.
  2. Save report locally saves the generated text, category, optional note and report time to this idea. It does not add user-written answers, the full transcript, keys or connection settings. A Result report includes the idea’s generated write-up, questions, suggestions, unedited AI drafts and coverage gaps, not the complete exported interview. Generated text itself may contain private details. Cancel saves nothing; a failed save keeps the form for retry.
  3. After saving a report for the still-current unanswered question, Ask a different question uses a distinct built-in checklist question on that same turn and dimension. It records no answer or skip and changes no coverage. Your unsent draft remains editable. If no different question is available, the error says so and keeps the current question.

Saving does not send the report to the developer or a model provider. Reports stay with the idea and appear in its markdown export and JSON backup; sharing those files also shares the reports. Deleting the idea deletes its local reports, not copies you have already shared. The optional Open email to developer action uses the confirmed privacy contact and opens an email composer containing only the report’s generated text, category and note. Review and send it there; an opened composer is not proof of delivery.

This reporting interface is Android-only by the requested native development scope, not a claim of Play approval. The shared session and export contract preserves reports in web imports, backups and exports, but the web app has no Report controls yet.

What the native interface checks prove

The repository’s optional Android device workflow has a evidence=makeover acceptance route. It exercises real onboarding, the explicit Voice/Type choice, typed and suggestion answers, wrap-up, Results, Copy and native Save/Share cancellation, the library, Settings and backup/import recovery. Its model/check/speech/service effects use dummy or scripted data; isolated voice phase frames are labelled as such and never fabricate level bars.

Rendering-enabled managed emulators measure compact, expanded and short-landscape windows, both themes and font scales 1.0, 1.3 and 2.0. The evidence includes the actual keyboard, system-navigation clearance, reachable controls, session/selection through rotation and automated heading, role, name, state and status semantics. Manifests record achieved dp/density and the tested source commit; a large image alone is not tablet evidence. Long-content and keyboard checks cover every requested font/window/theme; additional list, error, dialog and voice recovery stress states use font scale 2.0. A run is evidence only after its selected test, complete passed manifests and actual screenshots have been checked.

These checks do not establish physical-phone recognition, microphone contention, screen-off survival, live hosted-speech quality or a usability study. Manual TalkBack and switch-access checks remain unperformed; automated semantics do not certify either. Scripted permission-result tests cover microphone denial and optional notification denial without claiming a physical permission or recognition result. See the native acceptance commands and artifact requirements.

The focused evidence=dictation route uses the real manual Interview, capture owner and recogniser with controlled callbacks, not a drawn listening state. It checks Start/Stop, literal editable drafts, error and long-text states, report cancellation and Settings on compact and expanded rendering-enabled emulators, both themes at font scales 1.0, 1.3 and 2.0. A missing microphone grant is accepted through the real system dialog on that owned emulator; no recording, real recogniser, spoken output, service or hosted request runs. Require the selected passing test, complete clean-SHA manifests and inspected original screenshots. This does not certify physical recognition, speech quality, manual TalkBack or #89.

The focused evidence=reporting route uses the same native recorder on rendering-enabled compact and expanded emulators, both themes and font scales 1.0, 1.3 and 2.0. It checks actual question/suggestion/history/Result/Ideas/voice reachability, a pending session-lock save, a refused report write with retry, local export and no-answer replacement. Its voice output and service are scripted; it does not open a real email app, contact a model or certify a physical device. Require its selected passing test, complete clean-SHA manifests and inspected screenshots, not just a successful dispatch.

Play Console: microphone foreground service

Maintainer declaration copy for App content → Foreground service permissions, not a Play publication step. Select microphone and the use case Background Audio Access. The manifest declares FOREGROUND_SERVICE_MICROPHONE; the separate microphone runtime permission and interview-text agreement are still required. See Google’s FGS requirements and the publishing walkthrough.

Functionality (paste into the declaration)

IdeaForge offers a user-started, hands-free idea interview. From an Interview the user taps Hands-free interview (or chooses Start with voice for a new idea), then allows microphone access. A microphone foreground service keeps the active interview able to listen for answers and voice commands when the user switches apps or turns the screen off. With notification permission, an ongoing notification shows Pause and Exit. Pause stops microphone capture and speech, keeps the available captured words as an unsent draft, and requires an explicit Resume tap. Exit stops the service and returns to the same idea for typing without submitting an answer or requesting a write-up. The service does not start at boot or restart after process death.

Impact of deferral or interruption (paste into the declaration)

If start is deferred, the hands-free interview cannot listen when the user requests it. If interrupted, it cannot continue receiving the current answer or commands; words not yet recognised or transcribed may be lost. Explicit Pause preserves the draft words already available. The user can Resume deliberately or Exit and type; the app does not silently reopen the microphone after a stopped run.

Record and review the video

Run the repository’s Android device workflow with evidence=microphone-demo on the intended clean commit. Its opt-in pixel2Api34Voice managed emulator uses a standard Google APIs image and checks the installed native recogniser and text-to-speech services before recording. The test explicitly selects Android’s real default recognition service through an existing test seam, not scripted recognition: the stock emulator’s advertised on-device engine lacks usable English support. It runs the real on-device screenrecord utility through Android UiAutomation’s shell transport with a 55-second recording limit: Interview, Hands-free interview, the real system microphone and notification Allow dialogs, the hands-free stage, the real notification’s Pause/Exit controls, then Exit back to the same typed interview. It checks actual active audio recording and the foreground service, then verifies that Exit removes both and its notification.

Download android-microphone-demo-<SHA> from that workflow run. Require a passed manifest for the intended commit, a 30–60-second actual MP4, nonzero selected-test execution and all decoded video-*.png frames. Watch the clip and inspect the decoded permission, listening, notification and Exit frames before using it. The debug interview model and private setup data are scripted; native speech, permission dialogs, microphone, service and actions are not simulated. Default-service selection is test-only; this is not proof of the preferred on-device recogniser, physical-phone, speech-quality or screen-off-survival behavior. Artifacts expire after 14 days: the maintainer must retain the MP4, upload the reviewed video to unlisted YouTube, and paste that durable video URL into Play Console. The workflow never uploads to YouTube or Play.

Get the debug APK

The app needs Android 10 (API 29) or newer. The debug build’s application id is io.github.jaypetez.ideaforge.debug, so it installs beside the signed release build rather than replacing it.

Build it. With JDK 21 and the Android SDK installed, from a clone of the repository:

cd android
./gradlew :app:assembleDebug
# Windows: gradlew.bat :app:assembleDebug
# APK: android/app/build/outputs/apk/debug/

Or download it. Every successful CI run uploads the debug APK as the ideaforge-debug-apk artifact on its workflow run page. Artifacts need a GitHub sign-in and expire after 14 days. The download is a zip; extract the .apk first.

Get the signed release APK

Each successful GitHub release after signing and privacy-contact setup carries ideaforge-VERSION.apk, signed with the release key, and a SHA256SUMS file. Its application id is io.github.jaypetez.ideaforge, different from the debug build’s, so the two install side by side, each with its own ideas and keys. If the latest release has no APK, signed releases have not begun yet.

  1. Download ideaforge-VERSION.apk and SHA256SUMS from the release’s assets.
  2. Check the hash: sha256sum --check --ignore-missing SHA256SUMS.
  3. Check the signer with apksigner from the Android SDK build tools: every reported signer or SDK range must use the one app-signing certificate whose SHA-256 digest equals the fingerprint in SECURITY.md (ignore case and colons). If it does not, do not install it.
  4. Install it with adb install -r, as below. Opening the file on the phone instead may need the extra steps in Play Protect and unknown apps.
apksigner verify --print-certs ideaforge-VERSION.apk
adb install -r ideaforge-VERSION.apk

Android updates an installed release only with an APK signed by the same key, so a later release installs over it and keeps its data.

Releases also carry ideaforge-VERSION.aab and the bundle’s R8 mapping.txt, both covered by SHA256SUMS. The bundle is for Play upload, not direct installation. Its separate upload key authenticates the upload; Play signs the generated device APKs with the enrolled app-signing key. The maintainer must enrol the same app-signing key if Play and GitHub APKs are to share the published fingerprint. The upload certificate is not the APK trust pin. This does not mean Play distribution is available yet; see the key and bundle policy.

Install on the emulator

  1. In Android Studio’s Device Manager, create a virtual device (AVD) with a system image of API 29 or newer, and start it.
  2. Install it with one of the commands below: Gradle from the android/ directory, or adb for a downloaded APK.
  3. Open IdeaForge from the emulator’s app drawer.
./gradlew :app:installDebug
adb install -r app-debug.apk

-r replaces an installed copy and keeps its data, so your ideas and keys survive an update.

Install on a phone over USB

  1. On the phone, open Settings, then About phone, and tap Build number seven times to enable Developer options.
  2. In Developer options, turn on USB debugging.
  3. Connect the phone with a USB cable. When the phone asks Allow USB debugging? and shows the computer’s RSA key fingerprint, allow it.
  4. Check that adb devices lists the phone as device, then install with adb install -r, as below.
adb devices
adb install -r app-debug.apk

unauthorized in adb devices means the RSA prompt has not been accepted yet. Unlock the phone and look for it, or reconnect the cable.

Install on a phone over wireless adb

Wireless debugging needs Android 11 or newer, and the phone and computer on the same network.

  1. Enable Developer options as above, then turn on Wireless debugging in Developer options.
  2. Open Wireless debugging and choose Pair device with pairing code. Note the IP address, port and six-digit code it shows.
  3. Pair with that address, port and code, then connect and install as below. The connect port is the one on the main Wireless debugging screen, not the pairing port.
adb pair 192.168.1.23:37155 123456
adb connect 192.168.1.23:41733
adb install -r app-debug.apk

Play Protect and unknown apps

Google Play Protect may scan or warn about an app that did not come from Google Play. That is expected for a debug build signed with a development key, and for a release APK from GitHub rather than Google Play. Installing the APK by opening the file on the phone, rather than with adb, also needs the Install unknown apps permission for the app that opens it, such as your file manager or browser.

Google is rolling out developer verification for apps installed on certified Android devices. At the time of writing, Google’s developer verification FAQ says that apps installed using ADB do not require verification. This is why the steps above use adb install. Installing an unverified APK file directly on the phone may need the extra steps that FAQ describes.

Connect a provider

Hosted. Anthropic, OpenAI, Groq and OpenRouter take your own key. The key is encrypted with a key held in Android Keystore and sent only to that provider’s fixed https address. Groq’s free tier is the cheapest way to start.

On your own network. Ollama (local), LM Studio (local) and Another local server need no key, and the app never sends one to them. Unlike the web app, which only reaches the computer it runs on, the Android app accepts a server on a private network: loopback, 10.x, 172.16–31.x, 192.168.x, 100.64–127.x, link-local, IPv6 ULA and .local names. A public address, or a name that resolves to one, is refused.

Onboarding and Settings show an unencrypted HTTP warning for a local server outside loopback, including 10.0.2.2 on an emulator. Interview text sent over that connection is readable to network observers. Prefer https:// with a certificate trusted by the device and a matching server name; an untrusted self-signed certificate is not accepted automatically. Loopback addresses do not show the LAN warning; a tunnel or adb reverse can still forward that connection elsewhere. This warning does not replace the separate interview-text agreement.

Where the app runs Server address for Ollama on your computer
Emulator http://10.0.2.2:11434/v1. The emulator maps 10.0.2.2 to your computer’s loopback; onboarding has a button that fills it in.
Phone over USB Run adb reverse tcp:11434 tcp:11434 and keep http://localhost:11434/v1. Run it again after reconnecting the phone.
Phone on Wi-Fi The computer’s private address, such as http://192.168.1.20:11434/v1. Ollama must listen on the network (OLLAMA_HOST=0.0.0.0), which exposes it to everything else on that network too.

LM Studio works the same way on its port, 1234. See Local models and Docker for running the server itself.

Move ideas between Android and the web

Android and the web app use the same backup file. On Android, under Settings → Your data, choose Backup ideas or Import ideas. On the web, Settings → Your data offers Backup ideas and Import ideas. Move the file however you like: a cloud drive, email to yourself, or adb push.

Android’s own cloud backup and device-to-device transfer are turned off for the app, so a new phone starts empty until you import a backup. Keys never move: set up the provider again on the new device.

For developers

The project layout, the golden-vector contract with the JavaScript core, and the CI job are described in CONTRIBUTING.md. The build and emulator procedure is the shared android-verify skill.