Repository navigation
Releases: zeeshanhaque21/nanoMuse
Release list
nanoMuse v1.0.3-fork.1 (sanitized fork, Android APK, release-signed)
nanoMuse v1.0.3-fork.1 — sanitized fork release
Tracking upstream v1.0.3 ("Helm").
| Upstream release | https://github.com/nano-muse/nanoMuse/releases/tag/v1.0.3 |
| Upstream tag object | ff835524b0ced890dd0738ed48f4d5ef36e19b31 |
| Upstream tag commit (peeled) | 34a950c82977f20006d19d87d2241fe1f7071e7c — an ancestor of upstream/main, so the release needed no separate commit integration |
| Sanitized fork commit | 51dfee7455f692d4d2044712992038403cde7a74 (fork/main, the merge of PR #20) |
| Fork tag | v1.0.3-fork.1 — annotated, object cf4ea3ccf2ca5b1a1f5b05b5e233eeb332b046e0, peeled commit 51dfee7455. Never the raw upstream commit |
| Merged fork PR | #20 |
Assets
| File | Size | SHA-256 |
|---|---|---|
nanoMuse-1.0.3-arm64.apk |
39,054,703 bytes | b686214349a7ee801304881a4d1e5c828badb79e13b77d9af9982aea4df43ded |
nanoMuse-1.0.3-arm64.apk.sha256 |
— | the checksum above |
Built from the sanitized fork tag on this machine:
git checkout v1.0.3-fork.1
ANDROID_HOME=<filtered SDK shim, build-tools 36.0.0> bash scripts/release-apk.sh 1.0.3
Upstream binary assets are never copied — they may still contain the .cn backend and
omit every fork-only change below. Nothing here came from nano-muse/nanoMuse's release.
Why the build needed an SDK shim
scripts/release-apk.sh picks the newest build-tools and greps apksigner's output for
Signer #1 certificate …. build-tools 37.0.0 renamed those lines to V2 Signer: certificate …, so the grep matches nothing and set -e aborts the script after
assembleRelease has already produced a correctly signed APK. The run therefore ran the
pipeline against a shim ANDROID_HOME whose build-tools/ contains only 36.0.0 (the
newest version that still prints the Signer #1 form), with platforms, ndk, cmake,
platform-tools and licenses symlinked to the real SDK. This is a toolchain-drift issue
in the script, not a defect in the merged tree; it is recorded here rather than papered over.
APK verification actually performed
| Check | Result |
|---|---|
| Signature | CN=nanoMuse fork, OU=release, O=nanoMuse fork, L=unset, ST=unset, C=US — a real release key, not CN=Android Debug |
| Signer SHA-256 | 811846edf105767ca3e54cdafe5e2cad9e8e3348b1e54aefe6dbee2827512c00 — the same key as v0.1.34-fork.1 … v1.0.2-fork.1, so this build updates an installed copy in place |
| Badging | package: name='io.github.nanomuse.app' versionCode='46' versionName='1.0.3', application-label:'nanoMuse', arm64-v8a |
| Checksum | shasum -a 256 -c → nanoMuse-1.0.3-arm64.apk: OK |
| Backend scan | the APK was unzipped in full and grepped for nanomuse\.cn, demo\.nanomuse\.dev, nano-muse\.github\.io and cloud\.nanomuse — no hits |
Sanitization
The canonical scan (maintenance/RUNBOOK.md) leaves 19 files, every one classified:
attribution prose (docs/zh/cloud.md, docs/zh/every-device.md), legal text
(docs/zh/privacy.md), a deploy-artifact filename (cloud/README.md), immutable prior-run
evidence, the runbook itself, this run's own evidence, and three absence-assertion tests. The
active surfaces (nanomuse/, web/src/, cloud/nanomuse_cloud/, harness/*/src/,
desktop/, android/src/, nanomuse/server/static/) carry no nanomuse.cn — the
active-surface grep and the static-bundle grep both return nothing.
The relay seam is cloud.base_url / NANOMUSE_CLOUD_BASE_URL only; there is no default
relay, and an empty relay raises relay_unconfigured before any network I/O.
Fork-only changes kept
Google Calendar over OAuth; vault-backed MCP headers; configurable relay hosting;
signed-out relay editing; bundled desktop Playwright/Chromium; the GitHub-only update check
with an opt-in mirror; source: 'github' | 'mirror' | 'none' in the desktop shell.
Platform limitations (honest signing status)
- The Android APK is signed with the fork's release key. Verified above.
- The macOS desktop build is ad-hoc signed (
codesign -s -): the fork has no
MAC_CERT_P12_BASE64/ notarization secrets, so Gatekeeper will ask for Open Anyway in
System Settings → Privacy & Security. It is not notarized. - No Windows installer is produced by this run.
- iOS has no sideload path in this run; the iOS sources are only parsed, not built.
nanoMuse v1.0.2-fork.1 (sanitized fork, Android APK, release-signed)
nanoMuse v1.0.2-fork.1 — sanitized fork release
Tracking upstream v1.0.2 ("Trim").
| Upstream release | https://github.com/nano-muse/nanoMuse/releases/tag/v1.0.2 |
| Upstream tag commit | 7c91811ef16a34fd575c8614fad2ca754088d763 |
| Sanitized fork commit | the sanitized commit this run produced on fork/main; its exact SHA is in completion.md |
| Fork tag | v1.0.2-fork.1 (annotated) on the sanitized commit — never the raw upstream commit |
| Merged fork PR | #17 |
| Also tracks | v1.0.1 (Ballast), v1.0.0 (Keel) — the same sanitized commit |
Assets
| File | Size | SHA-256 |
|---|---|---|
nanoMuse-1.0.2-arm64.apk |
38,852,775 bytes | 43c3832ed99b7e3cae38cbcc771f5d43197a4c8dd5593100a3d056a1dbb0499e |
nanoMuse-1.0.2-arm64.apk.sha256 |
— | the checksum above |
The APK was built from the sanitized commit on this machine
(scripts/release-apk.sh 1.0.2 → ./gradlew :app:assembleRelease).
Upstream binary assets are never copied — they may still contain the .cn backend and
omit every fork-only change below.
APK verification actually performed
| Check | Result |
|---|---|
| Signature | CN=nanoMuse fork, OU=release, O=nanoMuse fork — a real release key, not CN=Android Debug |
| Signer SHA-256 | 811846edf105767ca3e54cdafe5e2cad9e8e3348b1e54aefe6dbee2827512c00 — the same key as v0.1.34-fork.1, so this build updates an installed copy |
| Badging | io.github.nanomuse.app, versionName=1.0.2, versionCode=45, arm64-v8a |
| Checksum | shasum -a 256 → recorded in the .sha256 asset |
Sanitization
The canonical scan (maintenance/RUNBOOK.md) leaves only 13 files, every one classified:
attribution prose (docs/zh/cloud.md, docs/zh/every-device.md), legal text
(docs/zh/privacy.md), a deploy-artifact filename (cloud/README.md), immutable prior-run
evidence, this runbook, and three absence-assertion tests. The only other files the scan
reports are this run's own four evidence files, which necessarily quote the scan command. The
active surfaces (nanomuse/, web/src/, cloud/nanomuse_cloud/, harness/*/src/,
android/src/, nanomuse/server/static/) carry no nanomuse.cn.
The relay seam is cloud.base_url / NANOMUSE_CLOUD_BASE_URL only; there is no default
relay, and an empty relay raises relay_unconfigured before any network I/O.
Fork-only changes kept
Google Calendar; vault-backed MCP headers; configurable relay hosting; signed-out relay
editing; bundled desktop Playwright/Chromium.
nanoMuse v1.0.1-fork.1 (sanitized fork, Android APK, release-signed)
nanoMuse v1.0.1-fork.1 — sanitized fork release
Tracking upstream v1.0.1 ("Ballast").
| Upstream release | https://github.com/nano-muse/nanoMuse/releases/tag/v1.0.1 |
| Upstream tag commit | 4f56f9654a6c7f5f7b3f934da4f04f5172e45c42 |
| Sanitized fork commit | the sanitized commit this run produced on fork/main; its exact SHA is in completion.md |
| Fork tag | v1.0.1-fork.1 (annotated) on the sanitized commit — never the raw upstream commit |
| Merged fork PR | #17 |
| Also tracks | v1.0.2 (Trim), v1.0.0 (Keel) — the same sanitized commit |
Assets
| File | Size | SHA-256 |
|---|---|---|
nanoMuse-1.0.2-arm64.apk |
38,852,775 bytes | 43c3832ed99b7e3cae38cbcc771f5d43197a4c8dd5593100a3d056a1dbb0499e |
nanoMuse-1.0.2-arm64.apk.sha256 |
— | the checksum above |
The APK is the one built from the sanitized commit (source versionName is upstream's
1.0.2; the fork release tag is v1.0.1-fork.1). Signature CN=nanoMuse fork, OU=release, O=nanoMuse fork, signer SHA-256 811846ed… — the same key as every prior fork release.
Upstream binary assets are never copied.
Sanitization
Same as v1.0.2-fork.1: the canonical scan leaves 13 classified files, and the only others are
this run's own four evidence files, which necessarily quote the scan command. The active
surfaces carry no nanomuse.cn; the relay seam is cloud.base_url / NANOMUSE_CLOUD_BASE_URL
only, with no default relay and a relay_unconfigured error before any network I/O.
Fork-only changes kept
Google Calendar; vault-backed MCP headers; configurable relay hosting; signed-out relay
editing; bundled desktop Playwright/Chromium.
nanoMuse v1.0.0-fork.1 (sanitized fork, Android APK, release-signed)
nanoMuse v1.0.0-fork.1 — sanitized fork release
Tracking upstream v1.0.0 ("Keel").
| Upstream release | https://github.com/nano-muse/nanoMuse/releases/tag/v1.0.0 |
| Upstream tag commit | a4b3a7aecbab83727ee1961aa726561f9cb08528 |
| Sanitized fork commit | the sanitized commit this run produced on fork/main; its exact SHA is in completion.md |
| Fork tag | v1.0.0-fork.1 (annotated) on the sanitized commit — never the raw upstream commit |
| Merged fork PR | #17 |
| Also tracks | v1.0.2 (Trim), v1.0.1 (Ballast) — the same sanitized commit |
Assets
| File | Size | SHA-256 |
|---|---|---|
nanoMuse-1.0.2-arm64.apk |
38,852,775 bytes | 43c3832ed99b7e3cae38cbcc771f5d43197a4c8dd5593100a3d056a1dbb0499e |
nanoMuse-1.0.2-arm64.apk.sha256 |
— | the checksum above |
The APK is the one built from the sanitized commit (source versionName is upstream's
1.0.2; the fork release tag is v1.0.0-fork.1). Signature CN=nanoMuse fork, OU=release, O=nanoMuse fork, signer SHA-256 811846ed… — the same key as every prior fork release.
Upstream binary assets are never copied.
Sanitization
Same as v1.0.2-fork.1: the canonical scan leaves 13 classified files, and the only others are
this run's own four evidence files, which necessarily quote the scan command. The active
surfaces carry no nanomuse.cn; the relay seam is cloud.base_url / NANOMUSE_CLOUD_BASE_URL
only, with no default relay and a relay_unconfigured error before any network I/O.
Fork-only changes kept
Google Calendar; vault-backed MCP headers; configurable relay hosting; signed-out relay
editing; bundled desktop Playwright/Chromium.
v0.1.41-fork.1 (sanitized fork, Android APK, release-signed)
v0.1.41-fork.1 - sanitized fork, release-signed Android APK
Upstream tag: v0.1.41.
Resolved upstream release commit: 3507091ced84cdb61eb6b6d08e0315cfd9d357cc.
Pinned merged upstream main: 9d7fc7ac005ce32271444cb302fb6860d019276c, including 136 commits after that release.
Sanitized fork tag target: df0b3e35986496aa27d48388d5cc24b205252e6e.
Reviewed/tested PR head: b1b55c1a03518458bf881724ff661ebb023ccf72, identical source tree to the merge.
Merged PR: #15.
Upstream prerelease status: false.
This release is scoped to the validated Android APK and checksum listed below.
The Android APK was rebuilt from this sanitized tag with JDK 17 and passes signature verification with Android build-tools 34 and 37.
APK: nanoMuse-0.1.41-arm64.apk, 38,953,918 bytes, package io.github.nanomuse.app, version 0.1.41, versionCode 42.
SHA-256: dd9a699075c355ae8545165ea1726e0119f2ef7c8ffb4418969a9cc097766584.
Fork signing certificate SHA-256: 811846edf105767ca3e54cdafe5e2cad9e8e3348b1e54aefe6dbee2827512c00; it is not the Android debug key.
Archive integrity and the unpacked endpoint scan pass with zero nanomuse.cn or demo.nanomuse.dev matches.
Both packaged proot copies match the native binary rebuilt with the NDK's llvm-readelf; its generated loader workaround offset is 1120, not the failed initial generation's 0.
Only this release-signed APK and its SHA-256 are eligible assets.
No upstream binaries are reused.
The fork retains configurable private relay hosting, Google Calendar and credential-vault MCP integration, while removing active upstream backend defaults and website navigation.
It repairs offline packaged activation, sync account isolation and stale errors, SQLite shutdown, framework-link packaging and fork-tag publication guards.
Exact reviewed-head CI passed 15 checks with one tag-only skip, and a fresh native advisor approved the merge.
Mac packages passed local ad-hoc signature, runtime, route and bundled Chromium smoke checks, but are not notarized and are not release assets here.
Full iOS native builds, signed Windows release artifacts and phone installation remain unverified.
The stock APK release helper successfully assembled but stopped at its certificate-display grep because build-tools 37 changed the output format.
The remaining naming, checksum and verification steps were performed independently without weakening the signing check or altering the immutable tag.
That helper compatibility bug needs a separate source fix.
All four hosted tag-triggered workflows succeeded on the exact sanitized commit: Test Suite, harness bundle, Docker image and desktop app.
All four desktop build platforms passed, and the harness and desktop release-upload jobs correctly skipped the fork tag.
No unsigned desktop or harness release assets were automatically attached.
The uploaded APK's GitHub-reported digest matches the locally verified SHA-256.
The separate main-only Website job is blocked because GitHub Pages is not configured on the fork; no public site has been enabled as a workaround.
Mac deployment is complete with a verified 0.1.37 backup and installed-runtime/browser checks; the unrelated local relay was preserved.
With explicit approval for a brief disconnect, the Jetson relay was upgraded from 0.19.0-fork.1 to 0.22.0-fork.1 using graceful shutdown without forced kill.
Its private /healthz returns HTTP 200 with ok: true and version 0.22.0, and Docker reports healthy.
Credentials, loopback-only port binding, data mount, network and restart policy were preserved; the old container and integrity-checked database backups remain available.
Migration and old-image rollback startup were tested against an isolated live-database snapshot first.
Phone installation and on-device app behavior remain unverified.
v0.1.37-fork.1 (sanitized fork — Android APK, release-signed)
nanoMuse v0.1.37-fork.1 — sanitized fork release
Tracking upstream v0.1.37 ("Weave").
| Upstream release | https://github.com/nano-muse/nanoMuse/releases/tag/v0.1.37 |
| Upstream tag commit | 10a699280e02827cdae5c81ca1093cda1dea5208 |
| Sanitized fork commit | ac5877f86d71ce157b408d6c977c1243ff65837d (merge of PR #11 on fork/main) |
| Fork tag | v0.1.37-fork.1 (annotated) on the sanitized commit — never the raw upstream commit |
| Merged fork PR | #11 |
| Also tracks | v0.1.36, v0.1.35 (same sanitized commit) |
Assets
| File | Size | SHA-256 |
|---|---|---|
nanoMuse-0.1.37-arm64.apk |
33,626,874 bytes | 93dc51204fac1c1c6406c957ed76f19e8c85d15c657041832673471d11dae41e |
nanoMuse-0.1.37-arm64.apk.sha256 |
— | the checksum above |
The APK was built from the tagged commit on this machine (./gradlew :app:assembleRelease).
Upstream binary assets are never copied — they may still contain the .cn backend and omit
every fork-only change below.
APK verification actually performed
| Check | Result |
|---|---|
| Signature | CN=nanoMuse fork, OU=release, O=nanoMuse fork — a real release key, not CN=Android Debug |
| Signer SHA-256 | 811846edf105767ca3e54cdafe5e2cad9e8e3348b1e54aefe6dbee2827512c00 — the same key as v0.1.34-fork.1, so this build updates an installed copy |
| Badging | io.github.nanomuse.app, versionName=0.1.37, versionCode=38, arm64-v8a |
.cn scan of the signed APK |
0 files with nanomuse.cn across all 592 entries; classes.dex, resources.arsc, AndroidManifest.xml all clean |
| Upstream release refs in the dex | 0 — all three mobile updaters read this fork's releases |
| Checksum | shasum -a 256 → recorded in the .sha256 asset |
The scan was run against the signed artifact, not the source tree, because the shipped APK is
what a phone actually receives. That mattered: a source-only grep missed a second Android updater
(com/openminis/app/data/UpdateChecker.kt) that still polled upstream's releases.
Fork changes on top of upstream
PR #11 merged upstream v0.1.34 → v0.1.37 and removed every active reference to the unwanted
nanomuse.cn backend.
The backend contract: the fork never contacts, links to, or defaults to nanomuse.cn or any
.cn cloud backend. Defaults are empty and the operator configures their own relay via
NANOMUSE_CLOUD_BASE_URL / cloud.base_url. Where a required default was removed, the app raises a
clear configuration error before any network I/O.
Sanitized at the owning configuration layer, never by global replacement:
| Surface | After |
|---|---|
nanomuse/server/update.py |
this fork's GitHub releases first; mirror opt-in via NANOMUSE_UPDATE_INDEX_URL, empty by default |
harness/…/src/desk.ts |
GitHub first, RELEASES_INDEX = '', optional configured mirror retained |
harness/…/src/nudges.ts |
NUDGES_ORIGIN = '' — the feature stays off until a relay is configured |
Android community/UpdateCheck.kt |
fork releases; INDEX_URL = "" guarded, so no empty-URL request |
Android com/openminis/app/data/UpdateChecker.kt |
fork releases (a second, separate updater) |
iOS NanoMuseUpdateCheck.swift |
fork releases; indexURL guarded |
iOS NanoMuseSettings.swift |
privacy link points at this fork's tracked docs/privacy.md, never force-unwrapped empty |
| web + desktop download links | the fork's releases page |
Upstream features kept and verified wired, not merely present: CloudSettings.sync, the console
conversation-sync card with its i18n keys in both languages, the desktop SyncControls at both call
sites, and upstream's new sync/one-thread documentation.
Fork-only features preserved: Google Calendar, vault-backed MCP headers, configurable relay hosting,
signed-out relay editing, bundled desktop Playwright/Chromium, and the private relay override.
Checks on the tagged commit
| Check | Result |
|---|---|
CI Ruff lint / Ruff format |
pass |
CI Mypy |
pass — no issues in 128 source files |
CI Tests |
pass (matrix: ubuntu py3.11/3.12/3.13, macOS, Windows) |
CI web app build — eslint, vitest, tsc, "Built app is committed" |
pass |
CI Android debug APK arm64-v8a, docker build, harness bundle, gateway tests |
pass |
CI Commits — DCO sign-off, Conventional Commit subjects |
pass |
| Total CI on the tested head | 15 checks, all pass, 0 failures |
Local cloud/tests |
91 passed |
Local demo/showcase/gateway/tests |
40 passed |
Local web npm run check |
pass — tsc clean, 51 tests |
Local harness tsc + node --test |
pass — 132 tests |
Pre-existing failures, proven not regressions
pytest -m "not live" reports 4 failures on pristine upstream v0.1.37 and the identical 4
after this merge (test_config ×2, test_memory_goals, test_skills) — all environment-sensitive
(vault placeholder resolution, PST/PDT timezone, a glob). Verified by running the identical command
on the upstream commit, on the pre-review fork head, and on the merged head. No failure is unique
to this fork.
Review
A separate fresh-context adversarial review audited the diff and returned mergeable after
fixes. Both major findings were real and are fixed in this release:
- The emptied mirror index was still fetched unconditionally on Android and iOS — caught by
Request.Builder().url("")throwing (swallowed, so no crash, but a guaranteed-to-fail request on
every check). Both now guard, matching the runtime and harness. - The mobile version lookup still read upstream's releases while the download button pointed at
the fork. Both now read this fork. A follow-up scan of the built dex found a third updater with
the same problem, also fixed.
The regression test now walks the entire Android and iOS source tree rather than listing files, so a
fourth updater cannot slip in behind named checks.
Honest platform limitations
- macOS and Windows desktop builds are not attached. The fork has zero GitHub Actions secrets,
so no signed or notarized macOS or Windows artifact is possible here. Release those yourself from
the tagged commit. - iOS is not attached. No sideload path on this host, and the Xcode build needs two prebuilt
native inputs (ProviderCustomization.xcconfig,Rclone.xcframework) that are git-ignored and not
present. Swift sources were verified withswiftc -parse(clean), which is a parse check, not a
device build. - The APK signing key is the app's permanent identity. If it is lost, no future APK can update an
installed copy, because Android requires the same signing key for every update. The key is stored
outside this repository atandroid/nanomuse-release.jks(git-ignored); back it up. - Remaining
.cnstrings inside the APK are third-party bring-your-own-key model providers in the
bundledlibgojni.so(ModelScope, MiniMax, Moonshot, SiliconFlow, iFlytek, Ark, TBox, SCNet) —
not the nanoMuse backend, and not contacted without the user's own key.
Historical references, preserved not rewritten
CHANGELOG.md, docs/releases/**, docs/readme/**, cloud/deploy/nanomuse-hk/**, demo/**,
docs/privacy.md, docs/roadmap.md, site/README.md and README.md's release history still mention
upstream's host. Those are attribution and history; they were reported, not edited.
🤖 Generated with Claude Code
v0.1.36-fork.1 (sanitized fork — Android APK, release-signed)
nanoMuse v0.1.36-fork.1 — sanitized fork release
Tracking upstream v0.1.36 ("Thread").
| Upstream release | https://github.com/nano-muse/nanoMuse/releases/tag/v0.1.36 |
| Upstream tag commit | 74329deb6e47fbb2781a3e89e77987a3e80bd704 |
| Sanitized fork commit | ac5877f86d71ce157b408d6c977c1243ff65837d (merge of PR #11 on fork/main) |
| Fork tag | v0.1.36-fork.1 (annotated) on the sanitized commit — never the raw upstream commit |
| Merged fork PR | #11 |
| Also tracks | the other v0.1.3x upstream releases (same sanitized commit) |
Assets
| File | Size | SHA-256 |
|---|---|---|
nanoMuse-0.1.37-arm64.apk |
33,626,874 bytes | 93dc51204fac1c1c6406c957ed76f19e8c85d15c657041832673471d11dae41e |
nanoMuse-0.1.37-arm64.apk.sha256 |
— | the checksum above |
The APK is the 0.1.37 / versionCode 38 build, produced from the tagged sanitized
commit on this machine (./gradlew :app:assembleRelease).
Upstream binary assets are never copied — they may still contain the .cn backend and omit
every fork-only change below.
APK verification actually performed
| Check | Result |
|---|---|
| Signature | CN=nanoMuse fork, OU=release, O=nanoMuse fork — a real release key, not CN=Android Debug |
| Signer SHA-256 | 811846edf105767ca3e54cdafe5e2cad9e8e3348b1e54aefe6dbee2827512c00 — the same key as v0.1.34-fork.1, so this build updates an installed copy |
| Badging | io.github.nanomuse.app, versionName=0.1.37, versionCode=38, arm64-v8a |
.cn scan of the signed APK |
0 files with nanomuse.cn across all 592 entries; classes.dex, resources.arsc, AndroidManifest.xml all clean |
| Upstream release refs in the dex | 0 — all three mobile updaters read this fork's releases |
| Checksum | shasum -a 256 → recorded in the .sha256 asset |
The scan was run against the signed artifact, not the source tree, because the shipped APK is
what a phone actually receives. That mattered: a source-only grep missed a second Android updater
(com/openminis/app/data/UpdateChecker.kt) that still polled upstream's releases.
Why an earlier upstream release ships the newest APK
v0.1.35, v0.1.36 and v0.1.37 are all contained in the same sanitized merge commit
(ac5877f86d71ce157b408d6c977c1243ff65837d), because one PR merged all three upstream
releases at once. Fork tags must sit on the sanitized fork commit that contains each
upstream release, so all three tags share that commit - and therefore all three carry the
same build. Only the source provenance differs per tag.
Fork changes on top of upstream
PR #11 merged upstream v0.1.34 → v0.1.37 (0.1.35, 0.1.36, 0.1.37) and removed every active reference to the unwanted
nanomuse.cn backend.
The backend contract: the fork never contacts, links to, or defaults to nanomuse.cn or any
.cn cloud backend. Defaults are empty and the operator configures their own relay via
NANOMUSE_CLOUD_BASE_URL / cloud.base_url. Where a required default was removed, the app raises a
clear configuration error before any network I/O.
Sanitized at the owning configuration layer, never by global replacement:
| Surface | After |
|---|---|
nanomuse/server/update.py |
this fork's GitHub releases first; mirror opt-in via NANOMUSE_UPDATE_INDEX_URL, empty by default |
harness/…/src/desk.ts |
GitHub first, RELEASES_INDEX = '', optional configured mirror retained |
harness/…/src/nudges.ts |
NUDGES_ORIGIN = '' — the feature stays off until a relay is configured |
Android community/UpdateCheck.kt |
fork releases; INDEX_URL = "" guarded, so no empty-URL request |
Android com/openminis/app/data/UpdateChecker.kt |
fork releases (a second, separate updater) |
iOS NanoMuseUpdateCheck.swift |
fork releases; indexURL guarded |
iOS NanoMuseSettings.swift |
privacy link points at this fork's tracked docs/privacy.md, never force-unwrapped empty |
| web + desktop download links | the fork's releases page |
Upstream features kept and verified wired, not merely present: CloudSettings.sync, the console
conversation-sync card with its i18n keys in both languages, the desktop SyncControls at both call
sites, and upstream's new sync/one-thread documentation.
Fork-only features preserved: Google Calendar, vault-backed MCP headers, configurable relay hosting,
signed-out relay editing, bundled desktop Playwright/Chromium, and the private relay override.
Checks on the tagged commit
| Check | Result |
|---|---|
CI Ruff lint / Ruff format |
pass |
CI Mypy |
pass — no issues in 128 source files |
CI Tests |
pass (matrix: ubuntu py3.11/3.12/3.13, macOS, Windows) |
CI web app build — eslint, vitest, tsc, "Built app is committed" |
pass |
CI Android debug APK arm64-v8a, docker build, harness bundle, gateway tests |
pass |
CI Commits — DCO sign-off, Conventional Commit subjects |
pass |
| Total CI on the tested head | 15 checks, all pass, 0 failures |
Local cloud/tests |
91 passed |
Local demo/showcase/gateway/tests |
40 passed |
Local web npm run check |
pass — tsc clean, 51 tests |
Local harness tsc + node --test |
pass — 132 tests |
Pre-existing failures, proven not regressions
pytest -m "not live" reports 4 failures on pristine upstream v0.1.37 and the identical 4
after this merge (test_config ×2, test_memory_goals, test_skills) — all environment-sensitive
(vault placeholder resolution, PST/PDT timezone, a glob). Verified by running the identical command
on the upstream commit, on the pre-review fork head, and on the merged head. No failure is unique
to this fork.
Review
A separate fresh-context adversarial review audited the diff and returned mergeable after
fixes. Both major findings were real and are fixed in this release:
- The emptied mirror index was still fetched unconditionally on Android and iOS — caught by
Request.Builder().url("")throwing (swallowed, so no crash, but a guaranteed-to-fail request on
every check). Both now guard, matching the runtime and harness. - The mobile version lookup still read upstream's releases while the download button pointed at
the fork. Both now read this fork. A follow-up scan of the built dex found a third updater with
the same problem, also fixed.
The regression test now walks the entire Android and iOS source tree rather than listing files, so a
fourth updater cannot slip in behind named checks.
Honest platform limitations
- macOS and Windows desktop builds are not attached. The fork has zero GitHub Actions secrets,
so no signed or notarized macOS or Windows artifact is possible here. Release those yourself from
the tagged commit. - iOS is not attached. No sideload path on this host, and the Xcode build needs two prebuilt
native inputs (ProviderCustomization.xcconfig,Rclone.xcframework) that are git-ignored and not
present. Swift sources were verified withswiftc -parse(clean), which is a parse check, not a
device build. - The APK signing key is the app's permanent identity. If it is lost, no future APK can update an
installed copy, because Android requires the same signing key for every update. The key is stored
outside this repository atandroid/nanomuse-release.jks(git-ignored); back it up. - Remaining
.cnstrings inside the APK are third-party bring-your-own-key model providers in the
bundledlibgojni.so(ModelScope, MiniMax, Moonshot, SiliconFlow, iFlytek, Ark, TBox, SCNet) —
not the nanoMuse backend, and not contacted without the user's own key.
Historical references, preserved not rewritten
CHANGELOG.md, docs/releases/**, docs/readme/**, cloud/deploy/nanomuse-hk/**, demo/**,
docs/privacy.md, docs/roadmap.md, site/README.md and README.md's release history still mention
upstream's host. Those are attribution and history; they were reported, not edited.
🤖 Generated with Claude Code
v0.1.35-fork.1 (sanitized fork — Android APK, release-signed)
nanoMuse v0.1.35-fork.1 — sanitized fork release
Tracking upstream v0.1.35 ("Accord").
| Upstream release | https://github.com/nano-muse/nanoMuse/releases/tag/v0.1.35 |
| Upstream tag commit | 48fd40d896da9d3ef1dfc56a6eb38395231b413d |
| Sanitized fork commit | ac5877f86d71ce157b408d6c977c1243ff65837d (merge of PR #11 on fork/main) |
| Fork tag | v0.1.35-fork.1 (annotated) on the sanitized commit — never the raw upstream commit |
| Merged fork PR | #11 |
| Also tracks | the other v0.1.3x upstream releases (same sanitized commit) |
Assets
| File | Size | SHA-256 |
|---|---|---|
nanoMuse-0.1.37-arm64.apk |
33,626,874 bytes | 93dc51204fac1c1c6406c957ed76f19e8c85d15c657041832673471d11dae41e |
nanoMuse-0.1.37-arm64.apk.sha256 |
— | the checksum above |
The APK is the 0.1.37 / versionCode 38 build, produced from the tagged sanitized
commit on this machine (./gradlew :app:assembleRelease).
Upstream binary assets are never copied — they may still contain the .cn backend and omit
every fork-only change below.
APK verification actually performed
| Check | Result |
|---|---|
| Signature | CN=nanoMuse fork, OU=release, O=nanoMuse fork — a real release key, not CN=Android Debug |
| Signer SHA-256 | 811846edf105767ca3e54cdafe5e2cad9e8e3348b1e54aefe6dbee2827512c00 — the same key as v0.1.34-fork.1, so this build updates an installed copy |
| Badging | io.github.nanomuse.app, versionName=0.1.37, versionCode=38, arm64-v8a |
.cn scan of the signed APK |
0 files with nanomuse.cn across all 592 entries; classes.dex, resources.arsc, AndroidManifest.xml all clean |
| Upstream release refs in the dex | 0 — all three mobile updaters read this fork's releases |
| Checksum | shasum -a 256 → recorded in the .sha256 asset |
The scan was run against the signed artifact, not the source tree, because the shipped APK is
what a phone actually receives. That mattered: a source-only grep missed a second Android updater
(com/openminis/app/data/UpdateChecker.kt) that still polled upstream's releases.
Why an earlier upstream release ships the newest APK
v0.1.35, v0.1.36 and v0.1.37 are all contained in the same sanitized merge commit
(ac5877f86d71ce157b408d6c977c1243ff65837d), because one PR merged all three upstream
releases at once. Fork tags must sit on the sanitized fork commit that contains each
upstream release, so all three tags share that commit - and therefore all three carry the
same build. Only the source provenance differs per tag.
Fork changes on top of upstream
PR #11 merged upstream v0.1.34 → v0.1.37 (0.1.35, 0.1.36, 0.1.37) and removed every active reference to the unwanted
nanomuse.cn backend.
The backend contract: the fork never contacts, links to, or defaults to nanomuse.cn or any
.cn cloud backend. Defaults are empty and the operator configures their own relay via
NANOMUSE_CLOUD_BASE_URL / cloud.base_url. Where a required default was removed, the app raises a
clear configuration error before any network I/O.
Sanitized at the owning configuration layer, never by global replacement:
| Surface | After |
|---|---|
nanomuse/server/update.py |
this fork's GitHub releases first; mirror opt-in via NANOMUSE_UPDATE_INDEX_URL, empty by default |
harness/…/src/desk.ts |
GitHub first, RELEASES_INDEX = '', optional configured mirror retained |
harness/…/src/nudges.ts |
NUDGES_ORIGIN = '' — the feature stays off until a relay is configured |
Android community/UpdateCheck.kt |
fork releases; INDEX_URL = "" guarded, so no empty-URL request |
Android com/openminis/app/data/UpdateChecker.kt |
fork releases (a second, separate updater) |
iOS NanoMuseUpdateCheck.swift |
fork releases; indexURL guarded |
iOS NanoMuseSettings.swift |
privacy link points at this fork's tracked docs/privacy.md, never force-unwrapped empty |
| web + desktop download links | the fork's releases page |
Upstream features kept and verified wired, not merely present: CloudSettings.sync, the console
conversation-sync card with its i18n keys in both languages, the desktop SyncControls at both call
sites, and upstream's new sync/one-thread documentation.
Fork-only features preserved: Google Calendar, vault-backed MCP headers, configurable relay hosting,
signed-out relay editing, bundled desktop Playwright/Chromium, and the private relay override.
Checks on the tagged commit
| Check | Result |
|---|---|
CI Ruff lint / Ruff format |
pass |
CI Mypy |
pass — no issues in 128 source files |
CI Tests |
pass (matrix: ubuntu py3.11/3.12/3.13, macOS, Windows) |
CI web app build — eslint, vitest, tsc, "Built app is committed" |
pass |
CI Android debug APK arm64-v8a, docker build, harness bundle, gateway tests |
pass |
CI Commits — DCO sign-off, Conventional Commit subjects |
pass |
| Total CI on the tested head | 15 checks, all pass, 0 failures |
Local cloud/tests |
91 passed |
Local demo/showcase/gateway/tests |
40 passed |
Local web npm run check |
pass — tsc clean, 51 tests |
Local harness tsc + node --test |
pass — 132 tests |
Pre-existing failures, proven not regressions
pytest -m "not live" reports 4 failures on pristine upstream v0.1.37 and the identical 4
after this merge (test_config ×2, test_memory_goals, test_skills) — all environment-sensitive
(vault placeholder resolution, PST/PDT timezone, a glob). Verified by running the identical command
on the upstream commit, on the pre-review fork head, and on the merged head. No failure is unique
to this fork.
Review
A separate fresh-context adversarial review audited the diff and returned mergeable after
fixes. Both major findings were real and are fixed in this release:
- The emptied mirror index was still fetched unconditionally on Android and iOS — caught by
Request.Builder().url("")throwing (swallowed, so no crash, but a guaranteed-to-fail request on
every check). Both now guard, matching the runtime and harness. - The mobile version lookup still read upstream's releases while the download button pointed at
the fork. Both now read this fork. A follow-up scan of the built dex found a third updater with
the same problem, also fixed.
The regression test now walks the entire Android and iOS source tree rather than listing files, so a
fourth updater cannot slip in behind named checks.
Honest platform limitations
- macOS and Windows desktop builds are not attached. The fork has zero GitHub Actions secrets,
so no signed or notarized macOS or Windows artifact is possible here. Release those yourself from
the tagged commit. - iOS is not attached. No sideload path on this host, and the Xcode build needs two prebuilt
native inputs (ProviderCustomization.xcconfig,Rclone.xcframework) that are git-ignored and not
present. Swift sources were verified withswiftc -parse(clean), which is a parse check, not a
device build. - The APK signing key is the app's permanent identity. If it is lost, no future APK can update an
installed copy, because Android requires the same signing key for every update. The key is stored
outside this repository atandroid/nanomuse-release.jks(git-ignored); back it up. - Remaining
.cnstrings inside the APK are third-party bring-your-own-key model providers in the
bundledlibgojni.so(ModelScope, MiniMax, Moonshot, SiliconFlow, iFlytek, Ark, TBox, SCNet) —
not the nanoMuse backend, and not contacted without the user's own key.
Historical references, preserved not rewritten
CHANGELOG.md, docs/releases/**, docs/readme/**, cloud/deploy/nanomuse-hk/**, demo/**,
docs/privacy.md, docs/roadmap.md, site/README.md and README.md's release history still mention
upstream's host. Those are attribution and history; they were reported, not edited.
🤖 Generated with Claude Code
v0.1.34-fork.1 (sanitized fork — Android APK, release-signed)
nanoMuse v0.1.34-fork.1 — sanitized fork release
Tracking upstream v0.1.34 ("Turns", code 35).
| Upstream release | https://github.com/nano-muse/nanoMuse/releases/tag/v0.1.34 |
| Upstream tag commit | 4f644c9c7ae6a5032b4cfb846a5b0824d1064c72 |
| Sanitized fork commit | 34aebbb9f476e596cd187e298fa0cf9c326a069f (fork/main) |
| Fork tag | v0.1.34-fork.1 (annotated) at the sanitized fork commit, never the raw upstream commit |
| Merged fork PR | #10 |
Assets
| File | Size | SHA-256 |
|---|---|---|
nanoMuse-0.1.34-arm64.apk |
37,680,266 bytes | aeeeb40bba08d3d967ef877957ebc55ab11c14db6c8616b84f95d38222207f13 |
nanoMuse-0.1.34-arm64.apk.sha256 |
— | the checksum above |
The APK was built from the sanitized fork commit on this machine
(./gradlew :app:assembleRelease). Upstream binary assets are never copied —
they may still contain the .cn backend and omit every fork-only feature below.
APK verification actually performed
| Check | Result |
|---|---|
| Signature | CN=nanoMuse fork, OU=release, O=nanoMuse fork — a real release key, not CN=Android Debug |
| Signer SHA-256 | 811846edf105767ca3e54cdafe5e2cad9e8e3348b1e54aefe6dbee2827512c00 |
| Badging | io.github.nanomuse.app, versionName=0.1.34, versionCode=35, arm64-v8a |
.cn scan of the signed APK |
classes.dex 0 hits, resources.arsc 0, AndroidManifest.xml 0, no .cn hostname anywhere across all 594 entries |
| Checksum | shasum -c → OK |
The .cn scan was run against the signed artifact, not the source tree, because
the shipped APK is what a phone actually receives.
Fork changes on top of upstream
- PR #10 — merged upstream 0.1.32 → 0.1.34 (27 commits) and removed every
active reference to the unwantednanomuse.cnbackend that upstream
reintroduced across 57 files. Full conflict resolutions, backend scan and
validation evidence: PR #10. - PR #4 — the earlier sanitized sync (upstream through v0.1.31, no default
.cnrelay). - PR #5 — web i18n + regenerated static bundle.
- PR #11 —
AGENTS.md, the daily maintenance runbook.
Fork-only features preserved across the merge, verified wired rather than
merely present: Google Calendar, vault-backed MCP headers (all three transport
paths), configurable relay hosting, signed-out relay editing, and bundled
desktop Playwright/Chromium.
Checks actually run on the tagged commit
| Check | Result |
|---|---|
CI Test Suite — ruff lint, ruff format, mypy, pytest, package build |
pass (ubuntu py3.11/3.12/3.13, macos, windows) |
CI web app build — eslint, vitest, tsc, "Built app is committed" |
pass |
CI docker build + smoke |
pass |
CI Commits (DCO sign-off, Conventional Commit subjects) |
pass |
CI harness bundle |
pass |
CI Showcase images / gateway tests |
pass (40 passed) |
CI Android — debug APK arm64-v8a |
pass |
pytest cloud/tests |
74 passed |
pytest demo/showcase/gateway/tests |
40 passed |
pytest tests/ |
412 passed, 4 skipped, 10 failed — all 10 reproduced on pristine fork/main and upstream/main |
Honest platform limitations
- Android APK: release-signed with a key generated for this fork on
2026-10-04. That key is the app's permanent identity. It is stored at
android/nanomuse-release.jks(git-ignored) in the fork's primary checkout.
Back it up now — if it is lost, no future APK can update an installed copy,
because Android requires the same signing key for every update. The key
material is deliberately not in this repository. - macOS / Windows desktop builds: no certificate secrets are configured on
the fork (gh-axi secret list→ 0), so a signed and notarized desktop build
cannot be produced here. A local ad-hoc-signed macOS build exists and was
installed and verified, but it is not redistributed as a release asset
because it is un-notarized. - iOS: no sideload path.
ios-testflight.ymlneeds App Store Connect
credentials the fork does not have; nothing was built or distributed to iOS. - Relay: the fork publishes no relay. The private Jetson relay was
redeployed from this sanitized commit and verified (0.14.0→0.17.0).
Deployments from this run
| Target | Outcome |
|---|---|
Jetson private relay (root@jetson-orin-nano) |
deployed nanomuse-cloud 0.14.0 → 0.17.0, healthy via /healthz, env parity identical (26 vars), data intact, previous image/container retained for rollback |
Mac /Applications/nanoMuse.app |
deployed 0.1.31 → 0.1.34, ad-hoc signed, backup at build/app-backups/nanoMuse-before-0.1.34-20261004-170543.app |
| Android APK | this release; not installed on any phone |