Moose v0.8.0 is an open source AI agent for iOS and Android powered by Pi Durable. Expo / React Native provides the interface, Pi Durable runs on the phone's Hermes runtime, and SQLite stores conversations and tasks. Model requests go directly to the provider; no Moose backend is required.
- Streaming chat, conversation history, and response cancellation. Long-press a sent message to resend it.
- Checkpoints and conversation branches. Save a checkpoint from the conversation's overflow menu and restore it from Tasks.
- Finite recurring tasks with saved progress, cancellation, and recovery after restarting the app.
- Install skills from HTTPS links and enable them independently for each conversation.
- Default file tools from
pi-durable-expo-env:read,write,edit, andworkspace_list. Each conversation has a private workspace on the device. - Optional experimental embedded iSH file and POSIX shell execution on iOS; see iOS setup.
- Optional experimental Termux file and command execution on Android, with in-app setup and connection. Native Termux device validation is still pending; see setup and limitations.
- OpenAI / Anthropic API keys and experimental ChatGPT / Codex subscription sign-in.
- Compact conversations, native message action menus, keyboard avoidance, and phone rotation between portrait and landscape. Assistant replies render Markdown headings, lists, quotes, code blocks, links, and horizontally scrollable tables.
Requires Node.js 22.19 or later. The Moose app itself does not run Node.js. Node is used for development, builds, and tests, and by the optional companion service inside Termux.
npm ci
npm run iosiOS requires macOS, Xcode, and an installed simulator. Android requires Android Studio, Java, the Android SDK, and a running emulator or a physical device with USB debugging enabled:
npm run android -- --deviceThe first run builds and installs a native development client. Expo Go is not supported, because browser subscription sign-in depends on a custom native TCP module.
Orientation is native configuration. Existing development clients need npx expo prebuild, followed by npm run ios or npm run android to rebuild and reinstall. Fast Refresh or a JavaScript update alone cannot unlock an older portrait-only client. Rotation follows the device's system orientation lock.
After installing the development client, start the development server with:
npm startPress i in the terminal to open the iOS simulator app, a to open the Android app, or j to open React Native DevTools. Ordinary UI changes support Fast Refresh. Run npm run bundle:runtime after changing src/runtime/ or authentication protocols. Run npm run ios or npm run android again after updating native dependencies.
If an Android device connected over USB cannot reach the development server, run adb reverse tcp:8081 tcp:8081 and connect to http://localhost:8081. Do not forward authentication callback port 1455; the phone listens on that port locally.
.github/workflows/build.yml runs when a v* tag is pushed or when Run workflow is selected manually. On a GitHub Ubuntu runner, it installs locked dependencies, generates the Pi runtime bundle, runs tests and type checks, then builds an APK with Expo Prebuild and Gradle assembleRelease. It does not use EAS cloud builds or require repository secrets.
After a successful build, download moose-android-test-<run-number> from the run's Artifacts section, extract it, and install the APK. The package includes JavaScript / Hermes assets and starts without Metro or a development computer. Model requests still require network access and your own credentials. Artifacts are retained for 14 days. Successful version-tag builds automatically create a regular GitHub release with the APK, moose-update.json, and service.mjs; manual builds only upload workflow artifacts.
The APK uses the generated Expo project's default test signing key and is intended for testing. Public distribution requires a separate long-term signing key. Changing signing keys may require uninstalling the old test build, which deletes local conversations and files. The iOS job is explicitly skipped with if: false; it does not build an IPA or upload to TestFlight.
Android builds with the updater check GitHub Releases on startup and when returning to the foreground, with at least six hours between automatic checks. In Settings, App updates supports manual checks, release notes, downloads, and cancellation. The app verifies the APK's SHA-256, package name, signing certificate, and build number before opening Android's installation confirmation. You may need to allow Moose to install apps. Installation and restart are never automatic.
Update releases require an APK and the matching moose-update.json. The tag workflow publishes both, using the tag for the version name and the workflow run number for Android versionCode. Existing users must manually install one build containing the updater. Test signing is retained; production signing migration is out of scope. iOS does not display this entry, and TestFlight and OTA are not integrated. See Android updates for the design and verification limits.
Open Settings, select a provider using its brand icon, choose a model, and save. OpenAI uses its wordmark, Anthropic uses its AI mark, and ChatGPT uses its knot logo.
OpenAI and Anthropic each require their own API key. API usage is billed separately under the provider's terms. Credentials are saved in the iOS Keychain / Android encrypted storage, never in the conversation database or repository.
Selecting ChatGPT provides two sign-in methods:
- Sign in to ChatGPT: Complete sign-in in the official browser page. The app temporarily listens on
127.0.0.1:1455for the OAuth callback, validates PKCE and state, and exchanges the authorization code for tokens. - Sign in with device code: Obtain a device code, open the official authorization page in a phone or desktop browser, sign in, and enter the code. Your account or workspace must permit device authorization.
Save the ChatGPT connection after authorization. Tokens are stored through SecureStore and refreshed automatically. You can cancel sign-in or sign out. Inference uses a separate Codex SSE channel; failures do not automatically switch to API-key billing. Account eligibility, quotas, and model access are determined by the provider.
If Google sign-in in a simulator stops at a passkey QR-code / Bluetooth step, choose another verification method or complete device-code authorization in a real phone or desktop browser. Full hardware sign-in flows require physical-device validation.
Automated tests use controlled responses, without signing into real accounts or sending billable requests. Real-account authorization, subscription eligibility, and quotas are outside automated validation. See subscription integration notes for protocol sources and validation records. Claude.ai / Claude Code subscription sign-in is not supported in this version; Anthropic uses API keys.
Recurring tasks run immediately for the first iteration, with an interval of at least one minute and a total of 2–100 iterations. Requests receive a stable ID before submission. Unconfirmed submissions can retry the same ID to avoid duplicate queue entries. Stopping a recurring task stops future scheduling; an already submitted response must be stopped separately in the conversation.
Android protects user-initiated finite runs with a bounded foreground service; see Android foreground execution. iOS may pause when suspended. Exact recurring execution times are not guaranteed. Reopening recovers committed state, and an overdue recurring task runs once before calculating its next interval. This version has no remote execution host or cross-device synchronization.
Restoring a checkpoint creates a new branch from the corresponding historical message and preserves the original conversation.
Skills support direct SKILL.md links and GitHub file, directory, or repository-root URLs. GitHub folders install a complete snapshot pinned to one commit: instructions, scripts, references, and binary assets, preserving relative paths. Limits are 128 files, 512 KiB per file (SKILL.md: 128 KiB), and 4 MiB total. Symlinks and submodules are rejected. GitHub folder refs must be a single-segment branch name or commit SHA. Direct SKILL.md links keep single-file imports.
The Skills screen includes downloadable presets for DuckDuckGo Search, Grilling, and FPL Copilot. Tap Install, then enable the Skill for the current conversation. Presets use the existing URL installer and are not preinstalled. DuckDuckGo imports its self-contained SKILL.md; Grilling and FPL Copilot import their folders. DuckDuckGo requires Python and ddgs in Termux. Installation does not provision these dependencies.
Skills are disabled by default. Enable one for the current conversation; only its instructions enter the initial context. View files shows its installed file list, sizes, commit, and selectable text previews; binary files show their size. The model can read installed text offline with skill_resource_read or copy the complete bundle into a fresh conversation-workspace directory with skill_workspace. Bash can run scripts from that directory when Termux is selected and required interpreters/dependencies are installed. Installation never runs scripts or installs dependencies. Local mode supports files but cannot run commands. Uninstall disables the Skill and removes its installed bundle; workspace copies remain conversation files. Legacy single-file imports retain authorized, cached remote text reads. See Skill folders.
Ask the model to write, edit, or read a file such as notes/todo.md. Files live in the current conversation's /workspace and survive app restarts. Other conversations cannot access them through these tools. There is currently no system document import entry point.
Checkpoints save conversation history, not file snapshots. Restoring one creates a new conversation with an empty workspace. It neither copies the original conversation's files nor rolls back disk contents. The original files remain unchanged.
Individual files are limited to 8 MiB. The default environment supports reading, writing, editing, and directory listing, but not command execution, script execution, or search. Android users can explicitly select Termux in Settings. Switching requires no app restart and does not migrate files. File contents read by tools enter the model context and may be sent to the selected provider.
The file environment uses the published npm package [email protected], with its version and integrity pinned in the lockfile. It does not depend on sibling source directories or local package archives. See file environment integration for update steps, the controlled native test entry point, and validation records.
See the step-by-step iOS iSH setup guide for first-time setup, controlled tests, everyday operations, troubleshooting and a device acceptance checklist.
The default iOS app needs only a model connection in Settings. To enable local shell execution, a developer must build a native client containing the embedded iSH core and enable it in the JavaScript bundle. There is currently no iOS execution-environment switch in Settings and no prebuilt IPA / TestFlight release from this repository.
You do not install the separate iSH app, Termux, a companion server, or Linux packages on the iPhone. The build bundles a pinned Alpine x86 root filesystem; Moose initializes a private copy for each conversation on first use. No port, pairing key, or shell permission prompt needs configuring on the phone.
The current build supports Apple Silicon macOS. Install full Xcode, open it once to finish setup, and install an iOS simulator runtime from Xcode Settings. Make sure Xcode is the active developer directory (xcode-select -p should point inside Xcode.app, rather than only Command Line Tools). Node.js must be 22.19 or later, as in local development.
With Homebrew already installed, install the native build tools:
brew install python meson ninja llvm lld libarchive pkgconf
export PATH="$(brew --prefix lld)/bin:$PATH"
export PKG_CONFIG_PATH="$(brew --prefix libarchive)/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
xcodebuild -version
xcrun --sdk iphonesimulator --show-sdk-pathKeep these exports in the terminal used for preparation. lld is required separately from LLVM. The preparation script does not install these tools itself.
From the Moose repository root on the PR #7 branch (or a later branch containing it):
npm ci
npm run prepare:ishPreparation downloads and verifies the pinned iSH source and Alpine rootfs, builds device and arm64 simulator libraries, and writes ignored artifacts under modules/moose-ish/vendor/. Keep network access available for the initial download. These generated files are local build inputs and must exist before native autolinking / compilation.
EXPO_PUBLIC_MOOSE_ISH=1 npm run iosThis builds and installs a native development client on the simulator and starts Metro. Expo Go cannot load iSH. Setting the flag alone cannot add the native module to an older client; rebuild after preparing or changing native dependencies.
For later development sessions, use the same flag when starting Metro:
EXPO_PUBLIC_MOOSE_ISH=1 npm startPress i to reopen the simulator app. The EXPO_PUBLIC_MOOSE_ISH value is included in the JavaScript bundle; it is not an iPhone environment variable or an in-app setting. Starting Metro without the flag selects the default local Expo files again. Finish or stop active tasks before switching builds/backends. Expo and iSH files are not automatically migrated; switching back preserves the other backend's files.
For a physical iPhone, connect it to the Mac and run EXPO_PUBLIC_MOOSE_ISH=1 npm run ios -- --device. Complete Xcode's device, development signing and provisioning setup for your Apple account, and enable Developer Mode if prompted by iOS. Physical-device installation, signing and background behavior have not been validated by this PR; the verified native path is the simulator.
Open Moose → Settings, select a provider, configure its API key or supported sign-in, and save. This is ordinary Moose model configuration; credentials are not passed to the guest shell. Start a conversation: read, write, edit, and bash share its /workspace. For example, ask Moose to write hello.txt, read it back with cat hello.txt through bash, and report the result. This conversational check makes model requests and may incur provider charges.
Developers can instead run the controlled native smoke without a real model account:
EXPO_PUBLIC_MOOSE_ISH=1 EXPO_PUBLIC_MOOSE_FILES_SMOKE=1 npm run iosThe test screen reports Moose filesystem smoke passed after controlled SSE drives Pi write/edit/bash/read, persistence and workspace-isolation checks. Omit EXPO_PUBLIC_MOOSE_FILES_SMOKE when returning to the normal app; restart Metro when changing these flags.
If startup reports iSH native module is missing, rerun prepare:ish and rebuild the development client. If downloads fail, check Mac network access and rerun preparation. Guest networking is intentionally disabled, so installing packages with apk or making guest network requests is unavailable; approved native HTTP tools remain separate. Shell commands use POSIX /bin/sh, run within explicit time/output/resource bounds, and may pause when iOS suspends Moose. Checkpoint branches have separate roots but do not snapshot files.
See iOS iSH execution notes for exact limits, verification commands and license/source obligations. Before distributing any binary linking iSH, resolve the whole-program license and corresponding-source requirements, even if the backend flag is off. This PR does not publish a binary or establish App Store approval.
Set up and connect Termux in Moose checks and installs Node and locking utilities, deploys the service bundled in the APK, pairs automatically, and connects. You do not need to download or copy service.mjs, copy a public key, type a service startup command, or restart Moose to switch environments.
First-time setup still requires these steps:
- Install a new Moose APK containing the native setup module. Older APKs and Expo Go do not include it; developers must rebuild the native client.
- Install and open Termux once. Wait for initialization to finish and a command prompt to appear.
- Open Moose → Settings → Execution environment, tap Allow command execution, and allow commands to run in Termux. If no system prompt appears, or you previously denied permission, tap Open system settings and allow it under Moose's app permissions / other permissions.
- On the same page, long-press to copy the one-time configuration command, tap Open Termux, paste and run it, then return to Moose. The complete command is:
mkdir -p ~/.termux && printf '\nallow-external-apps = true\n' >> ~/.termux/termux.properties && termux-reload-settings- Tap Set up and connect Termux. Keep Moose in the foreground with network access until checks, installation, and connection finish. The initial Termux package download may take several minutes. On success, Moose shows that Termux is connected and switches the current environment to Termux without restarting.
- Tap Run self-test (no model). It checks signed communication, temporary file writes/reads, and bash in a reserved diagnostic workspace, then removes its temporary directory. It does not use model credentials or change conversation files. A passing self-test checks this execution path at that time; it does not guarantee background availability.
The selected environment is separate from the most recent communication result and timestamp. View diagnostics shows up to 40 session-only metadata records that can be selected and copied; restarting Moose clears them. Records contain operation, local correlation number, result, time and duration, without paths, commands, content or credentials. A file-not-found response means the service responded; it is not a connection failure. Timeouts, calling-task cancellation and transport interruption are reported separately; an unexplained native cancellation is not attributed to the user or Android without evidence.
When Termux is selected, Moose checks its signed connection on foreground return and before starting a response or recurring iteration. If the service is unavailable, it attempts repair for up to 30 seconds, including time waiting behind setup. Failed checks prevent new responses from starting; use Check or repair connection in Settings for installation, missing permissions, incompatible services, or longer repairs. Recovery keeps the current runtime and never replays failed chat tools or acknowledges unknown command outcomes. Use Use local files to return to the local environment. Finish or stop active responses, pending submissions, and recurring tasks before switching. Switching does not migrate files or delete native databases or historical reports.
The service listens only on the phone's 127.0.0.1:18765. The temporary installation port also listens only on loopback. It transfers code bundled in the APK and verifies SHA-256, without shared-storage permission. Moose's private signing seed and model credentials are never passed to Termux. Android may suspend or terminate background processes, so continuous execution with the screen locked is not guaranteed.
Termux commands have that app's file and network permissions and can access other Termux files. Conversation directories and PRoot are not security sandboxes. Native tool permissions do not constrain bash network or file access. Cancelling setup stops waiting and temporary transfers, but does not roll back installed packages. An installer that has already finished downloading may still start the service.
See the step-by-step phone setup guide for common errors, migration from an existing manual service, and an acceptance checklist. See Termux notes for technical boundaries and validation records. Android device authorization, deployment, connection, and cancellation still require physical-device acceptance testing; tests and asset exports are not device validation.
These general native tools serve the default local environment and remain available on iOS and on Android without Termux. Termux mode hides overlapping HTTP, database, JSON import, document, and directory-listing tools, delegating complex execution to bash. It retains capabilities, skill_resource_read, and artifact_create for tool discovery, skill resources, and in-app report publication.
Existing native databases, documents, reports, and permissions are neither deleted nor migrated and remain available after switching back to the local environment. Files in Termux workspaces do not automatically appear in the reports list; explicitly call artifact_create to publish previewable HTML or text.
The model can use capabilities to inspect tool contracts and currently enabled skill IDs. Native tools support HTTPS GET, separate skill SQLite databases, declarative JSON imports, cross-conversation documents, and HTML / text reports. Tools work without installing or enabling a skill and default to the current conversation's private scope. Pass skillId only when accessing shared skill data; the skill must be installed and enabled in the current conversation. Skill resource reads always require a skill ID. Skill content cannot grant itself permissions.
The app requests authorization on first access to an HTTPS origin, database reads or writes, or cross-conversation skill documents. Grants apply only to the selected scope in the current conversation. General tools and individual skills have separate permissions, which can be revoked in Settings; revocation stops the current response. Database write permission does not include read permission. Tools do not use model-provider API keys, OAuth tokens, or browser cookies.
HTTP responses are stored by reference, limited to 8 MiB with a 30-second timeout. Redirects are checked and authorized individually. json_import transforms data on the device and writes it to SQLite without sending the entire JSON payload to the model. Databases use separate files and cannot access Pi internals. Queries generate parameterized SQL from table names, fields, conditions, ordering, and limits, return at most 200 rows, and do not accept arbitrary SQL. Migrations support creating tables and adding fields; writes support primary-key upserts.
Writes, imports, document changes, and report generation require a stable operationId. Retries reuse the ID; changing parameters while reusing an ID is an error. Data and operation receipts commit in one transaction. Failed batches roll back, and successful refresh timestamps advance only after a complete import commits. Execution is still not guaranteed while the app is suspended.
Databases, documents, and HTTP responses without a skill ID belong to the current conversation, survive restarts, and are inaccessible to other conversations or new checkpoint branches. Skill databases and shared documents survive restarts, conversation changes, and checkpoint branches; new conversations require fresh authorization. Uninstalling a skill revokes tool access but retains data for reinstallation. Conversation workspaces remain isolated, and checkpoints do not snapshot files. Individual documents and reports are limited to 512 KiB. Document and resource reads are paginated, and their contents may be sent to the selected model provider.
After generating a report, open Files and reports from the conversation's overflow menu to preview it, or tap Share or export to open the system share sheet. In-app HTML previews disable JavaScript, external resources, and navigation. Sharing requires an explicit user tap. Rebuild the development client after adding native dependencies.
See native tool design for tool boundaries, persistence semantics, and validation notes. Developers can open an isolated native test entry point with EXPO_PUBLIC_MOOSE_CAPABILITIES_SMOKE=1 npx expo start --dev-client. It uses a dedicated SQLite database and controlled responses without accessing user data or real models.
Use + beside the message field to select Files, Photos, or Take photo. Preview or remove attachments before sending; text is optional. Each message accepts up to 4 attachments, each no larger than 8 MiB. Photos are converted to JPEG with a maximum edge of 2048 pixels. The camera requests permission when used; no microphone permission is requested.
Images are sent as visual input to the selected vision-capable model. Other files are imported into the conversation's /workspace/attachments/<unique ID>/<filename> for its read tool. Importing a document does not add a PDF or Office parser. Files with the same name use separate directories.
Attachment bytes are saved with the stable request ID before submission, persist in message history, and are retained when retrying or resending. Checkpoint branches reimport the original historical attachment bytes; they do not copy later file edits or other workspace files. Unsent drafts remain in memory per conversation and are lost on app exit. Picker-owned cache copies are cleaned after capture or rejection. Content goes directly to the selected model provider, without a Moose upload backend.
Rebuild the native development client after adding the picker dependencies. See attachment design and validation for implementation details and test limitations.
npm run verify
npx expo-doctorverify covers runtime bundle generation, unit and integration tests, 3 real installer-script tests, TypeScript checks, the Pi Durable / SQLite / simulated Codex path without Node globals, and Android and iOS Hermes release asset exports.
Current validation coverage:
- iOS: Native debug build, installation, and operation on an iPhone 17 Pro simulator. Checks covered chat layout, message menus, keyboard avoidance, skill downloads and persistence, and local authentication callback listening and cancellation cleanup.
- Android: Debug APK compilation, installation on an Android 35 emulator, and controlled foreground-service SSE / local file-tool / next-round execution with SQLite commits, Activity destruction/recreation, notification stopping, and force-stop persistence passed. Physical-device Doze, vendor power policies, the full 30-minute timeout, and real Termux operations remain unverified. Release assets exported successfully. GitHub Actions successfully compiled a test APK containing the native Termux setup module. Phone installation, permission grants, and real Termux operations have not yet been validated.
- Expo Doctor: 19 of 20 checks passed. The remaining check concerns new-architecture metadata for the TCP library and missing public-directory metadata for the local Termux and iSH modules; this is not a fully passing result.
- File environment: The local package completed real file reads, writes, edits, SQLite reopening, and workspace isolation checks on the iOS simulator using controlled OpenAI SSE responses, without real credentials or billable requests.
dist/ contains JavaScript / Hermes release assets, not an APK or IPA. Build native apps locally or use the repository's EAS development, preview, and production configurations. EAS builds require your own Expo project, signing, and device configuration. EAS cloud builds and store publication have not been validated for this version. GitHub Actions test APK compilation is documented above.
- React Native Directory lists
react-native-tcp-socketas untested with the new architecture. The current iOS development build has been verified to run; Android physical-device compatibility remains unverified. - The dependency tree has documented upstream npm audit findings involving the Expo / Metro toolchain. Expo has not been forcibly downgraded to remove these warnings. See mobile feasibility notes.
App.tsx Conversation UI, navigation, and message menus
src/ui/ Tasks, skills, settings, and app state
src/runtime/ Pi Durable sessions, recurring tasks, checkpoints, and model adapters
src/auth/ Portable device-code and PKCE protocols with injected TCP callbacks
src/platform/ Expo SQLite, SecureStore, browser, fetch, and Hermes compatibility
src/storage/database.ts Serialized SQLite adapter and transaction isolation
src/skills/skills.ts Skill URLs, download limits, and instruction selection
scripts/ Runtime bundling, dependency audits, and portable runtime tests
tests/ Protocol, storage, task, and recovery tests
Pi Durable / AI / Chord are pinned to 1.3.0. Portable entry points are prebundled with esbuild, excluding Node credential autodiscovery and OAuth callback servers. Platform capabilities are injected explicitly. Generated src/generated/, ios/, android/, and dist/ directories are not committed and are regenerated during builds and validation.
See AGENTS.md for development constraints and chat layout notes for interface design. Brand icon sources and licenses are documented in assets/brands.
On Android, a user-initiated answer or finite task establishes a shared foreground service and notification before model work begins. The existing Hermes runtime and Pi Harness continue the same SSE, local tools and SQLite commits when the Activity is hidden. Returning to the app does not resubmit, reopen the Harness or resume it again. Notification permission is required; a denied permission or failed service handshake prevents model execution.
Automatic compaction runs as part of the active answer rather than as speculative background work. All active conversations share the service. The last run releases it; each continuous service generation has a 30-minute execution budget and a bounded partial wake lock. The notification's Stop action cancels all answers and recurring tasks, including future iterations. If JavaScript cannot acknowledge cancellation within 10 seconds, the native service terminates this process; a persistent cancellation marker is processed before recovery on the next manual launch. A missing startup handshake triggers cancellation after 15 seconds.
Recurring tasks do not hold the service while waiting. An iteration due while the app is hidden waits until Moose is visible unless another active run already holds the service. There is no scheduled background wakeup, boot receiver or automatic service restart. A tool requiring new permission stores the pending permission scope and prompts the user to open Moose; it never grants permission automatically. Termux is a separate app and is not kept alive by Moose's service. Switching execution environments is blocked while any conversation, repeat, pending request or foreground admission is active.
Chat shows the current task separately from historical reply attempts: running, retrying, waiting for network or authorization, completed, failed or stopped. Tap the task status or an attempt's Details for bounded, credential-redacted errors, stage, time and retry count. Native notification stop, budget expiry, startup timeout, permission loss, runtime destruction and service destruction keep distinct cancellation reasons. These diagnostics are persisted with the conversation (latest 200 events); they are separate from session-only Termux transport diagnostics.
Transient model failures use Pi's durable retry checkpoint, with at most three generation retries and exponential 2/4/8-second backoff. Reopening projects committed messages and tool results and reconciles already-settled outbox items; it does not resubmit a task on foreground return. A failed attempt that later recovered is labelled as history. Network waiting is inferred from a transport error with a scheduled retry, rather than a claim that connectivity has been measured. Authentication and quota errors are not retried automatically. An operation whose effects are unknown blocks further mutations across restart and context compaction; inspect its effects before choosing Review interrupted operation → Allow further changes. That action does not rerun the command. See background recovery design and validation.
Android’s ongoing notification shows committed execution progress. Background completion or failure posts one result alert per conversation; foreground results are silent. Tap a single-task or result notification to open its saved conversation without resubmitting it. Multiple active conversations share a count notification and the existing Stop-all action. Failure alerts use brief fixed categories without provider bodies or credentials. Task results can be muted separately in Android notification settings.
System reclamation, Doze, network loss and vendor power policies can still interrupt execution. Process death cannot preserve the original TCP connection or Promise, and recovery cannot guarantee a model is billed only once. Force-stop is respected. iOS retains its existing suspension behavior. The Android specialUse declaration describes finite AI work; this does not imply Google Play approval.
For a controlled native probe, rebuild the Android development client and run EXPO_PUBLIC_MOOSE_BACKGROUND_SMOKE=1 npx expo start --dev-client. Tap Run background probe, confirm the service starts, then press Home. After 15 seconds the probe should finish its file tool and second model round, commit SQLite and release its notification. The probe uses a separate database and controlled SSE, never real credentials or paid requests. Notification stopping can be checked during the delay. The same probe has a five/ten-minute lock test and a durable-results reader. For actual native network transport, start node scripts/background-probe-server.mjs on the development machine, then use Run network probe in the Android emulator; it connects only to the controlled local endpoint through 10.0.2.2:8106. No request is forwarded to a model service.