# Hermes Android 3.0.0 Stable 3.0.0 promotes the application code from [RC3](https://github.com/rusty4444/hermes-android/tree/9fa5c280e87b08cac5b1350017528cdd7f662560), with a new stable version/build identity, documentation and README artwork. This page covers the full change set since **2.1.33**, including changes first delivered in RC1 and RC2. [Download 3.0.0](https://github.com/rusty4444/hermes-android/releases/tag/v3.0.0) · [Full comparison](https://github.com/rusty4444/hermes-android/compare/v2.1.33...v3.0.0) · [Changelog](../../CHANGELOG.md) ## Upgrading Export an encrypted configuration backup before installing. The production package and signing identity remain unchanged, so the appropriate APK upgrades 2.1.33 or any 3.0 RC in place. Keep your backup password safe: backups can include connection credentials and imported private-key material. | APK | Device | Version code | | --- | --- | --- | | `app-arm64-v8a-release.apk` | Most current Android phones/tablets | `30032` | | `app-armeabi-v7a-release.apk` | Older 32-bit ARM devices | `30031` | | `app-x86_64-release.apk` | x86_64 Android devices/emulators | `30033` | The base build is `3003`. An older APK has a lower version code; returning to it can require uninstalling the app and restoring a backup. Installing this APK does not upgrade or configure your Hermes host or the optional mobile-push companion. ## Main changes - Choose from ten full-app colour palettes, independently of light, dark or system appearance. - Start in Chats, browse scheduled conversations in Crons, and archive or restore chats from their action menus. - Read completed replies in quiet mode and inspect collapsed details in Verbose Mode. Follow current work in the responding bar and see message-level local times. - Send guidance to an active Remote Gateway run; REST offers an explicit Stop and send action instead. - Browse shared files in More → Assets, preview images/PDF/text, download through Android's save picker, or share to another app. - Import optional PEM/P12 client certificates and carry them in encrypted configuration backups. - Enable automatic background notifications on supported phones after the operator configures the separate server companion. - Keep drafts, notifications and saved/live history under stricter account, turn and receipt ownership. Read application and third-party licence notices offline. ## Detailed changes since 2.1.33 The labels below distinguish new capabilities from changes and fixes to existing ones. Saved Memory facts, task inspection, local pins, Project moves, voice, uploads and stock Gateway reattachment remain available; they were not first introduced in 3.0. ### Appearance and device settings - **New:** Ten complete colour palettes: **Gold, Purple, Orange, Green, Blue, Red, Teal, Pink, Indigo and Cyan**. Colour selection is independent of System / Light / Dark brightness. Available from Settings → Appearance and the connection-screen palette button, including before connecting. - **Changed:** The selected palette covers backgrounds, cards, navigation, controls, menus, dialogs, chat bubbles, Markdown/code and the Hermes wordmark rather than merely changing one accent. Semantic failure/success/warning colours remain meaningful. Existing code blocks recolour without needing a new message. - **Fixed:** Appearance updates existing routes immediately without closing a chat or losing its draft. Palette and brightness survive restart and configuration backup/restore. Serialised saves and rollback prevent a failed older choice or a quickly dismissed picker from leaving the surviving app on the wrong colour. - **Changed:** Flutter-visible Android system chrome follows app appearance; gesture navigation is transparent and three-button navigation uses an OS-compatible themed surface to keep controls readable when app/OS brightness differ. Launcher icon/native splash remain branding assets; fullscreen media retains a deliberate black canvas. - **Fixed:** Appearance and other device-local Settings controls remain available while dashboard model settings are loading or have failed, instead of replacing the entire screen with a loader/error. Appearance is placed before server-model controls. ### Chats, Crons and archiving - **Changed:** Default navigation is **Chats → Crons → Projects → Activity → More**; Home is removed as a separate destination. Responsive bottom navigation / wider-screen rail remain. New chat is exposed on Chats; Crons has a job-manager shortcut. - **New:** A dedicated Crons conversation browser separates scheduled-job conversations from human Chats. It supports its own search, All / Recent / Archived filters and local pins, including older runs and conversations whose job was deleted. Script-only jobs without chats are not invented as conversations. - **Fixed:** Cron recognition includes persisted legacy non-hex job IDs and compression roots even when `source` is missing. Search/filtering does not reintroduce scheduled or other machine sessions into the human browser. - **Changed:** Compact **Needs you / Running now** summaries sit above the human chat list when relevant app-observed work exists, rather than duplicating Home's recent/completed conversation lists. The action summary can open the Activity overview. - **Changed:** More removes the duplicate Archived Quick Chats entry and unused Organisation / Pin, batch and undo / AI-assisted filing placeholders. **Automation** becomes **Agent**, grouping Cron, Skills and Memory. Archive access is through Chats → Archived, not removed from the app. - **Fixed:** Human and cron browsers share progressive session scans: a small first preview, incremental pages and no silent old 2,000-row ceiling. Repeated server pin backfills are deduplicated without skipping requested windows or falsely treating a pin-only page as end-of-history. - **Fixed:** Active, archived and Project/Quick metadata loading have separate readiness/error authority. Completed dashboard archive results can replace their own snapshot while active history is still pending. Refresh/retry performs fresh scope-specific I/O, preserves known rows on failure and does not falsely report an empty archive or classify every unknown Project chat as Unassigned. - **Fixed:** Late preference hydration supplies local pins without waiting on unrelated history. Standalone Search/Unassigned renames reconcile into retained Chats, and an older aggregate scan cannot overwrite a newer external title or confirmed archive/move. - **New:** Manual **Archive / Unarchive** actions in chat/list surfaces update the exact stored conversation and verify the result with an exact GET read-back. A long-lived parent owns the operation across route pop; stale list/search/paging responses cannot undo confirmed actions. Menus serialise competing row actions. - **Fixed:** Restoring an expired Quick Chat is successful only after the device-local retention change is durably saved; failed writes reload the speculative cache and remain retryable. Unresolved expired IDs produce incomplete/retry state. New-chat copy no longer promises automatic server archiving or guaranteed memory retention after 72 hours; the local Quick Chat policy itself was not newly introduced. ### Activity - **Fixed:** Activity is populated from real app-owned **stock** Remote Gateway turn observations, not only the experimental recovery-v2 journal. It also includes gateway chats updated within seven days, including REST-only connections and work started elsewhere. - **Changed:** App-observed needs-input, submitted/running, failed and completed states are distinct from **Status unconfirmed** / reconciling / outcome unknown. Server chat metadata is labelled **Updated**, not inferred running or completed; stale local running records are not permanent proof of active server work. - **New:** A bounded metadata-only operational Activity index survives restart. It retains conversation lineage roots so old/compressed entries open the current chat without duplicate continuation rows. It stores identifiers/state/times, not prompts, answers, titles, tool output or approval contents; finished/unknown records are bounded while unresolved records remain discoverable. - **Fixed:** Activity refreshes while actually visible, pauses under other tabs/routes and in the background, and supports pull-to-refresh. Partial/stale source coverage is labelled; bounded scans do not present exhaustive counts or definitive absence. Older metadata reads cannot resurrect an obsolete continuation or undo a newer title. ### Conversation, composer and recovery - **Changed:** **Verbose Mode off** is now a conversation-only prose view: human input and positively completed Hermes replies. Commentary, incomplete/failed replies, tools, reasoning, task/report cards and source diagnostics are hidden; approvals/input remain accessible and generated-file cards have their own presentation path. This is more than the old metadata toggle. - **Changed:** **Verbose Mode on** exposes retained detail but starts every expandable tool/reasoning/task/background/notice/message-detail section collapsed, even during active work or with gateway verbose hints. Manual choices survive updates and lazy scrolling within a visit, not a true close/reopen; a covering task inspector is not a new visit. The old explicit-Verbose open default is removed. - **New:** One responding bar above the composer shows current tools and short progress, **Reasoning**, delegated work or status such as compaction in either mode, without adding partial assistant bubbles to quiet chat. REST/SSE consumes supported reasoning/tool/status events; gateways without them retain the generic indicator. Completion removes it; terminal failure/uncertainty does not keep a typing spinner. - **New:** Local-time footers on human messages and completed Hermes replies in both densities/modes. Valid numeric server times take precedence; a tooltip distinguishes server recording from one-time send/receipt observation and includes full date. Missing/invalid history times stay absent. Earlier previews completing after later commentary keep their own timestamp. Device observations are not a new persistent receipt log. - **Fixed:** A chat opens at its latest **visible** message, including retained owner content before HTTP completes and a late history failure changing layout. Refresh/streaming/task inspection do not pull a reader away from older content; deliberate scrolling cancels opening/end alignment. - **New:** Separate **Stop** and **Send** remain available during work. Stock Remote Gateway Send uses `session.steer` as text-only guidance for the current run; legacy/non-steering transports explicitly **Stop and send** a new prompt instead. Stop remains independent while guidance acknowledgement is pending. Preparation, recovery, attachments and model changes keep their safety gates. - **Fixed:** Mid-run guidance clears only the submitted edit after confirmed acknowledgement, preserves newer typing/intentional clearing, keeps rejected/unconfirmed drafts and never automatically retries or silently falls back to a second prompt. A late ACK after termination is not claimed as consumed guidance; restored runs retain subsequent response output. Narrow-screen controls retain usable 48 dp targets. - **Fixed:** Stopping a new REST/SSE response before any text arrives no longer erases a previous completed reply. A stale post-response history read cannot erase received REST output; handover needs its own exact durable response ID, which the present SSE protocol does not provide, so the reply remains for that visit. - **Changed:** Saved Remote Gateway history and retained received output are independently presented instead of using an unproved baseline/text match to hide one source. Verbose wrappers and export preserve provenance and received outcome-unknown information. The large in-transcript received-output explanation moves to **Chat actions → About received output**. Received output is bounded/temporary, not an offline transcript archive. - **Fixed:** Saved/live duplication is removed **only when proven**: an owned successful `message.complete` supplies a valid complete `persisted_turn` receipt and a newer accepted physical history batch contains all exact addressed rows plus an independently completed final response. Replacement atomically removes covered live prose/tools/timeline/outcome scaffolds; matching text, idle status, numeric floors or a final row alone are insufficient. - **Fixed:** Proven canonical replacement context is shared with retained sibling/alias chat routes. Long turns can request fresh bounded context beyond page one; superseded context attempts can retry without spinning, cold/older paging retains its cursor, and a held read cannot revive a reply vetoed by a newer alias observation. No receipt means no universal duplicate-removal promise. - **Changed:** Recognised machine-authored user-role notices and preserved task lists become neutral, read-only **Background task** / **Background process** cards, hidden in quiet mode. They are not editable human prompts or retry targets. Typed model/personality switches, automatic continuations, internal notifications and delegation/process completions are covered; bounded legacy envelopes provide compatibility. - **Fixed:** Internal-message classification preserves public/hidden/model-only precedence, genuine steering/skill invocations, quoted examples and human follow-ups merged into a notice. Absorbed-message witnesses prevent legacy matching from swallowing human requests; retry ownership follows the surviving human message. The same policy and independent report expansion apply to delegated-task history. - **Fixed:** Local-to-stored identity handover keeps composer edits, intentional clears, retained reasoning/tool expansion identities and child observation authority. Delayed old-route saves or rejected submissions cannot steal a newer canonical draft. Physical preference reloads and failed hydration no longer turn unavailable draft storage into proof of an empty draft. - **Fixed:** Turn history/recovery now carries request-start and submission-observation authority through asynchronous work. Old idle/terminal events, pre-ACK recovery reads and losing alias owners cannot settle a newer turn or release Send early. Fresh create-empty evidence is consumed only for its first valid admission; uncertain submissions are never resent. Late tool IDs correlate only an unambiguous existing anonymous call, and terminal tools do not regress to running. - **Fixed:** Chat exports across transports respect public replacement content, including explicit empty/null replacements, rather than exposing hidden/model-only physical messages. Image-only history avoids empty-text placeholders. Task-history links and report expansion keep their own modal/scroll-storage ownership; task row labels pass the correct row ID/role arguments. ### Generated files, previews and web links - **New:** Native **More → Assets** discovers generated-file references from saved replies, with found-file/source-chat search, type filters, download/share and source-chat navigation. Scans are incremental, with more-chat / older-message controls and partial/retry reporting; successful batch reads are not repeated merely to retry a failed one. - **Changed:** File discovery is shared between timeline and Assets: explicit `MEDIA:` plus filesystem Markdown links and **successful `image_generate` producer results**, including image outputs omitted from the final answer. Files stay visible independently of verbose tool cards. This extends existing MEDIA cards; MEDIA delivery itself was already in v2.1.15. - **New:** File popups provide zoomable images, Android PDF page previews and selectable inert text (including recognised text/Markdown/JSON/CSV). Unsupported binaries show metadata and an honest no-inline-preview fallback while remaining downloadable/shareable. PDF rendering is native, off the UI thread and resource-bounded; it is not a new Office viewer. - **New:** Timeline cards and popup previews have direct native **Save/Download**, distinct from **Share**. Cancel does not report success; errors are retryable. Card/popup share cached bytes, and closing/replacing their owning card cancels active transfers rather than leaving hidden downloads. - **Changed:** Chat-delivery and Assets downloads share a **25 MiB per-file streaming limit**, including chunked/no-length responses and authentication retries. Files are fetched only after explicit user action; text/PDF previews have additional display bounds. Outgoing upload limits are a separate, pre-existing contract. - **New:** URL-only generated images can be fetched after a tap through a separate credential-free HTTPS client with bounded, HTTPS-only redirects. Gateway cookies, API bearer tokens and client certificates never go to the image host. File paths continue through authenticated saved Dashboard/profile/session context, not local Android paths. - **Changed:** Android requests the stock rich-chat `desktop` source on create/resume and adds versioned file-delivery guidance through existing protocols, including reused TUI sessions and REST/SSE. No Android companion/backend patch is required for attachment instructions. Literal slash commands and typed voice-stop phrases remain untouched; a bounded config read failure sends original text rather than risking a broken control. A confirmed `voice_stopped` acknowledgement does not wait for an agent terminal frame, and title generation receives the original human prompt rather than the appended note. The note is ordinary **saved user context**, hidden only from Android's recognised display/edit/export projections. - **Fixed:** HTTP/HTTPS links in replies, selectable-message dialogs and delegated-task transcripts open the external browser on tap. Gateway filesystem links retain file preview/download routing; code examples, unsupported schemes and untapped remote images remain inert. Link errors remain visible above the owning modal and are suppressed if that modal has already closed. ### Notifications and background protection - **New:** Simplified opt-in **Background notifications**: one enable action plus Android notification permission. An embedded Google-backed transport removes manual endpoint/key/chat-ID entry and the need for a separate distributor app on phones with working Play Services. External UnifiedPush remains an advanced, optional alternative for Google-free devices. This is not the first UnifiedPush implementation. - **New:** Automatic subscriptions negotiate **authorised current and future durable chats** under the verified login's live policy. Explicit operator owner-wide grants can cover new chats; restricted grants remain restricted. One installation binds one saved connection; existing explicit-session consent is not silently broadened and needs disable/re-enable to choose automatic scope. - **Fixed:** Setup explains the separate server companion, offers its operator-guide link, and distinguishes missing/disabled/outdated/unauthorised services from successful registration. Off-state availability probes are read-only, owned by the Settings lifetime and do not enable push, ask permission or clear a consent error. Phone retry cannot install server software. - **Fixed:** Durable registration/confirmation attempt journals recover lost server responses or local activation writes using fresh nonce/revision and a new encrypted challenge for the **same existing consent**. Pending is not Active; expired/missing proofs have a bounded wait and recover on foreground reconciliation rather than endless rotation. Endpoint renewal clears obsolete activation and tap authority. - **Fixed:** Paired server registration fences reject old delayed PUTs inside the authority transaction. Revocation of a not-yet-committed installation creates a terminal tombstone; old requests cannot resurrect disabled consent. The upgrade migration invalidates older proof/endpoint state and requires the fenced client. Observer event eligibility is frozen/rechecked against live ACL/durable scope, with installation/generation-bound event feeds for automatic mode. - **Fixed:** Saved-account edits/imports/removals invalidate bound push authority before committing changed metadata/secrets. Native mutation leases and storage completions belong to the Flutter **engine**, not an Activity: detach/reattach, orphan draining, queued old writes and live sibling engines cannot restore stale consent or enrol stale account metadata. - **Fixed:** Root notification navigation retains a consumed tap across pause/resume, revalidates account contents/credentials/profile, mutation epoch and push authority after each asynchronous boundary and authenticated lookup page, and coalesces compatible targets. Canonical aliases focus an existing chat rather than constructing duplicate routes; a stale older lookup cannot steal focus from a newer tap. - **Fixed:** Sensitive notification actions carry client-local account/mutation provenance and retain their captured dispatch owner. Stale, unscoped or changed-account approval/secret actions fail closed; ordinary safe chat navigation can still work. A push hint still cannot approve anything or submit/resubmit a prompt. - **Fixed:** Foreground protection starts only from successfully loaded/committed background policy, not failed hydration or optimistic settings. Targeted notification cleanup survives partial platform failures without cancelling another active chat's entries. Permission prompting and passive OS-state refresh have separate freshness/single-flight authority. These harden the existing one-service/per-chat-notification feature rather than introducing it. - **Fixed:** Companion dependency bounds now admit current Hermes cryptography generations (`cryptography>=44,<51` rather than `<48`). Current-host setup documentation and default-path tests distinguish API mounting from actually active turn hooks/sender workers, with admitted package management instead of raw environment mutation. ### Client certificates, connections and backups - **New:** Optional per-connection imported **client-certificate (mTLS)** authentication for certificate-enforcing HTTPS proxies: PEM certificate/key material, combined PEM, or PKCS#12 P12/PFX. Removal/rotation and saved metadata are supported. It does not replace normal API/dashboard authentication. - **Fixed:** A single content-sniffed picker can stage a PEM certificate/key pair in either order or import a combined/P12 identity. Android/iOS do not grey out valid certificate files because of extension→MIME filters. Password entry appears **after** a protected pick and retries without repicking; loaded-file layout is readable. Actual reads are capped at **1 MiB**, and obsolete selection/password callbacks cannot replace a newer choice. - **Fixed:** Import validates usable PEM identities through the actual TLS parser before reporting Loaded, preserves certificate-chain separators, supports encrypted PKCS#8 and traditional encrypted RSA PEM, and preserves exact passphrase bytes across reload and backup. P12 extraction does not retain an unnecessary container password. - **Fixed:** PEM key passphrases are kept in secure credential storage rather than plaintext connection preferences. Migration merges with existing secure API/dashboard secrets. Imported key material remains app-private files, with owned file leases through validation, queued account save/import, uncertain acknowledgement, rollback and route disposal; cleanup does not delete a still-referenced or live staged identity. - **New:** Encrypted configuration backup format v2 carries portable PEM identity contents and necessary encrypted-key passphrases, not device-specific paths, alongside the new palette. Older supported backups remain readable; a backup claiming a required but missing identity fails explicitly instead of silently restoring an unusable account. - **Fixed:** Backup merge/replace restores identities before account commit and rolls back attempted secure bundles as well as metadata/files on failure. Physical reload protects committed replacement files after a lost acknowledgement. If rollback itself fails, the error says restoration is incomplete; it does not falsely guarantee atomic restoration during a persistent storage outage. - **Fixed:** The connection's TLS identity is wired into independent list/history/recovery, REST/SSE, WSS, search/AI rewrite, task history, Memory, push API and authenticated download clients. Identity/password changes invalidate retained transport and push bindings. No certificate is lent to GitHub update checks or external image hosts; ordinary non-mTLS scope/receipt compatibility is retained. - **Fixed:** Saved connection list operations share physical transaction ownership across managers, protect prerequisites before mutation and isolate optional mutation observers. Public storage errors are sanitised rather than leaking provider detail; failed optional observers cannot break an account mutation. Unknown physical reference state retains files instead of destructively guessing. ### Offline licences and release integrity - **New:** **Settings → About → Licences** works offline and includes the application MIT text, Cinzel OFL text, embedded distributor notice/licence/relink instructions and Flutter dependency notices. A canonical root LICENSE records the README's existing MIT grant; it is not a new blanket relicensing of third parties. - **Changed:** Distribution includes embedded-Library notices and complete source/build material inside APK assets, plus **SHA256SUMS** and an exact-application **source/relink ZIP** beside the three APKs. A documented local-AAR replacement/relink path permits rebuilding without a Hermes production signing key. The upstream source licence is treated as LGPL-2.1-or-later despite its conflicting POM. - **Fixed:** Release publication is create-only and bound to the peeled remote tag / exact checkout. It verifies **all three** actual APK package/version/ABI codes, the single production signer and source/licence assets before publication; wrong/extra/malformed assets fail closed. Hosted `V2 Signer:` output is recognised without weakening pinning. PR quality also runs verifier/publisher/native-config regressions, and dedicated native/server CI has a pinned Gradle/runtime identity. Existing APKs are not silently clobbered. ## Compatibility and delivery limits - Quiet mode requires positive completion metadata for each reply. Older saved history without that metadata remains readable in Verbose Mode; a successful history fetch or idle socket does not prove completion. - Saved/live duplicate handover requires the optional complete `persisted_turn` receipt and fresh history containing every addressed row. Older or lagging gateways can retain both sources. Received output is bounded and temporary, not an offline transcript archive, and uncertain prompts are not resubmitted. - Remote Gateway guidance is text-only and an acknowledgement does not prove the agent acted on it. The app does not retry it on your behalf. REST Stop and send interrupts the current response before starting a new prompt. - Assets needs authenticated dashboard history/file access. It searches discovered references, not the full filesystem or every upload/tool output. Files may no longer exist. Downloads have a 25 MiB per-file limit; outgoing attachment limits are separate. Android PDF and text previews have additional display bounds. - The live-work bar shows only the events your server provides; it does not infer hidden reasoning. Activity is a bounded app-observed/recently-updated view, not a complete server audit log. - Push needs the separately installed, enabled and operator-authorised [mobile-push server companion](../mobile-push-server.md), with both its API and turn-hook/sender worker active. The current host supports the dashboard launch profile in trusted in-process mode; secondary-profile deployments that cannot forward verified login identity fail closed. Upgrade the paired client and companion together and check capabilities, not just the companion package version. - Built-in delivery needs working Google Play Services and Google's infrastructure, but no Firebase project, Firebase credentials or separate distributor app. Google-free devices need an external UnifiedPush distributor. One installation binds one saved connection; existing selected-session consent is not expanded without disable/re-enable. Pending does not mean Active. - Background delivery remains best-effort. Force stop, Doze, OEM battery restrictions, offline devices and revoked notification permission can delay or prevent it. Neither the foreground service nor push guarantees an uninterrupted connection. Push hints omit chat text and cannot approve actions or submit prompts. - Imported certificates use app-private files, not Android KeyChain/non-exportable hardware keys. mTLS does not replace API/dashboard authentication or bypass server trust. Physical-device private-CA and killed-process push behaviour need device-specific testing. - Embedded-library notices retain the upstream POM/source licence discrepancy and LGPL source/relink terms. Exact-source materials do not constitute legal clearance or F-Droid approval. See [the Library notice](../../third_party/embedded-push-notice.md) and [relink instructions](../../third_party/embedded-push-relink.md). - Some newer strings use the English fallback in existing non-English locales. This promotion does not change RC3's translations or upgrade its dependency set. ## Guides [Themes](../APPEARANCE_THEMES.md) · [Chat presentation](../chat-presentation.md) · [Sending while working](../sending-while-working.md) · [Assets and previews](../chat-assets.md) · [Background work](../android-background-work.md) · [Android push](../mobile-push-android.md) · [Server companion](../mobile-push-server.md) · [mTLS implementation and limits](../mtls-report.md) ## Credits Thanks to [@smhc](https://github.com/smhc) for optional client certificates in #166, the mobile picker/password improvements in #187 and the physical Android mTLS report. Maintainer follow-ups cover encrypted PEM, certificate chains, transaction ownership and transport integration. Earlier community contributors retain their acknowledgements in the [README](../../README.md#credits) and [NOTICE](../../NOTICE.md). Hermes Agent assisted with implementation, review, documentation and regression tests. Automated checks and demo-emulator captures do not establish private-CA or killed-process push acceptance on every phone. The GitHub release body records final validation; historical component reports are not the final release test count.