Data sovereignty
returned to you,
AI at your fingertips.
CLI-driven local AI × hardware-grade encryption.
Built for everyone who wants to own their data.
Knowledge · Social · Trading,
end-to-end, individual-first.
One foundation — hardware security + on-device AI + true decentralization. Three pillars stand independently and compose freely.
Knowledge Base
- ·Notes / docs / chat history — your personal second brain
- ·Hybrid search: BM25 + Qdrant vectors
- ·Hierarchical memory 2.0: working → short → long → core
- ·RAG-powered Q&A · code knowledge graph
Decentralized Social
- ·W3C DID v2 identity + verifiable credentials
- ·P2P end-to-end: Signal + libp2p + WebRTC
- ·Community / channel gossip cross-machine sync (v5.0.3.41+)
- ·Audit-grade Merkle envelopes + cross-machine distribution + external archival (B4 suite)
- ·Protocol bridge: ActivityPub · Nostr · Matrix
- ·Anti-censorship: Tor + domain fronting + satellite
Trading Assistant
- ·Multi-chain wallets: EVM family + Solana
- ·Cross-chain bridge: HTLC atomic swap + messaging
- ·zk-SNARK / zk-STARK generated locally
- ·DAO governance v2 · quadratic voting · treasury
Pull every digital footprint home —
into a vault that's yours alone.
Email · WeChat · Alipay · 8 AI chatbots · 7 social platforms · shopping · travel · Android system data —
22+ sources end-to-end pulled to local, untouchable by anyone else.
"Data sovereignty returned to individuals" is not a slogan — it's 22 real adapters, 5 built-in analysis skills, 1 local encrypted vault.
- · IMAP across all mail providers
- · Alipay statement CSV / PDF
- · 6 template extractors (bill/order/travel)
- · PDF decryption + transactions
- · DeepSeek · Kimi · Tongyi
- · Zhipu · Hunyuan · Qianfan
- · Coze · Dreamina · Doubao
- 9 / 9 vendors wired · Phase 10.2
- · WeChat (SQLCipher)
- · QQ · Weibo · Bilibili
- · Douyin · Xiaohongshu
- · Telegram · WhatsApp
- · Taobao · JD · Meituan
- · Amap · Baidu Map
- · Ctrip · 12306
- · Orders / logistics / footprints unified
- · Contacts · call log
- · SMS · location history
- · Android ADB backup
- · iOS iTunes encrypted
Add friends, message, post ——
with no platform in the middle.
Your identity is your own DID, messages are peer-to-peer end-to-end encrypted, communities sync across machines ——
no one can ban your account, delete your posts, or read your DMs.
- · W3C DID + verifiable credentials VC / VP
- · Social recovery + cross-device roaming
- · Reputation aggregation, no central accounts
- · Signal protocol + libp2p + WebRTC
- · Keys live only on both ends
- · Offline add + signaling relay fallback
- · WebRTC direct connect, sub-second setup
- · Full-screen lock-screen incoming calls
- · Local call history (FAMILY-67)
- · gossip cross-node distribution
- · Audit-grade Merkle envelopes
- · External archiving, offline-safe
- · ActivityPub C2S federation
- · Nostr NIP-01/04/09/25
- · Matrix threads & spaces
- · Tor + domain fronting
- · Satellite message channel
- · Multi-hop routing + cross-federation trust anchors
Your wallet, your keys,
your assets.
Multi-chain + cross-chain + zero-knowledge, signing entirely on-device ——
private keys never leave your device — no custody, no middlemen.
- · EVM chains + Solana
- · Local keys, hardware U-Key protection
- · Assets / balances / history aggregation
- · HTLC atomic swaps
- · Cross-chain messaging + bridging
- · Multi-sig swap / send
- · zk-SNARK / zk-STARK generated locally
- · Private, verifiable, no disclosure
- · compile / prove / verify pipeline
- · Quadratic voting
- · Treasury management + delegation
- · propose / vote / tally
- · Merkle Tree Certs M-of-N
- · libp2p / filesystem auto-discovery
- · Heterogeneous Ed25519 + SLH-DSA
- · Skill marketplace + usage stats
- · Token incentives (7 contribution types)
- · NFT mint / transfer
Your terminal,
your AI workbench.
No GUI required — chainlesschain runs local AI, agent coding, and multi-agent orchestration entirely in the terminal.
Your keys,
held in your hand.
U-Key / SIMKey hardware chips · keys never exported. AES-256 + SQLCipher full encryption. Signal end-to-end. Local Ollama inference — data never reaches the cloud.
USB security chip
Windows Koffi FFI talks directly to the SIMKey SDK. PIN-protected, auto-locks on repeated failure, all critical operations require physical confirmation. BLE/NFC wireless U-Key + biometrics.
SIM-card security chip
Android OMAPI / iOS eSIM API. USIM + 5G super-SIM across three Chinese carriers. Fingerprint / Face ID replaces PIN. 12 enhancements: eSIM OTA, TEE integration, post-quantum readiness.
Local Ollama
qwen2 / llama3 / deepseek-r1 inference on-device. 14+ cloud LLMs available but never required. Sensitive data auto-routes to local models — the cloud path is severed at the source.
Multi-agent, made into
repeatable engineering patterns.
Not concept demos. Each item is shipped, tested, and codified. Full changelog at docs.chainlesschain.com/changelog.
PDH analysis/collection fixes + FAMILY-67 call/notification UX + Android keyboard-overlap fix
PDH analysis pipeline: spending total now uses sumEventAmount (no longer undercounted by the per-subtype 5000-row cap); overview byApp/byType/total use facetCounts (no longer truncated by the 10k-row cap); timeline excludes app-usage baseline aggregate events. PDH query parsing: parseIntent adds income-amount phrasing + symmetric "how many/几" quantifiers; parseFilters removes income's bare "收到" mis-classification; parseTimeWindow "last N months" no longer overflows the month-end day and drops a whole month; "how much did I spend" without "总共" no longer mis-routes to list (it is a sum). PDH collection: Douyin usage-profile + watch-history vault ingest; Toutiao plaintext article reader (title in the share_info blob); a reproducible WeChat EnMicroMsg.db decrypt-and-ingest script. FAMILY-67 call/notification: network-drop reconnect grace (ICE DISCONNECTED no longer silently hangs); friend-connection self-heal (E2EE handshake only when the DataChannel is already connected); missed-call notification + CallStyle lock-screen incoming call + "stay online to answer" foreground service; friend message notifications deep-link into the right chat + runtime POST_NOTIFICATIONS request (Android 13+). Android keyboard overlap: a global imePadding under edge-to-edge fixes input fields being covered by the keyboard across every page in one place. IDE extensions: VS Code 0.33.0 / JetBrains 0.4.18 dedicated vision-model entry + first-run LLM config onboarding. Version surfaces: productVersion v5.0.3.120 → v5.0.3.121 / desktop 5.0.3-alpha.121 / Android versionCode 503121 / iOS build 121; shipped with 18 release assets.
FAMILY-67 friend call history + incoming ringtone + CLI network robustness
Call history: friend voice/video call terminal states are persisted to call_history via CallHistoryRecorder (incoming/outgoing, missed, audio/video type, and hangup reason); the friend profile "view call history" entry filters by friend DID or shows all (live Flow read). Incoming ringtone/vibration + outgoing ringback: incoming calls play the system ringtone + vibrate (respecting silent/vibrate mode), outgoing calls play ringback — fixes "no sound on incoming call". CLI network robustness: webhook notifiers, cc update / vcheck update-checks, and the provider connectivity probe all get timeouts (a dead endpoint no longer hangs forever); reputation / plugin revenue split reject NaN score/amount to avoid corrupting balances. Shipped with 18 release assets.
Friend P2P encrypted voice / video calls (P0–P3 + history + background calls + self-heal)
Adds 1:1 real-time voice / video calling on top of friend P2P encrypted messaging: pure P2P + DTLS-SRTP end-to-end encryption, control signaling relayed over the existing signaling server (same friend-DID routing as messages — delivers even if a DataChannel was never built), media over a dedicated WebRTC PeerConnection. P0 signaling state machine (ringing / accept / reject / hangup + glare arbitration + timeouts); P1 voice (reuses the message-side PeerConnectionFactory + ICE/TURN, earpiece / speaker routing); P2 video (lazily-built video PeerConnectionFactory with EglBase + codec factories, front-camera capture + remote full-screen + local PiP + camera flip); P3 background / lockscreen (foreground service keeps the mic alive when locked + full-screen incoming notification turns the screen on over the lock screen + proximity-sensor screen-off). System ringtone + vibration on incoming (respects silent / vibrate mode), ringback on outgoing; every call is persisted and viewable as call history on the friend profile. Also includes: missed-call notifications, system-level CallStyle answer/decline UI, a stay-online foreground service (receive calls when backgrounded/screen-off), a 20s reconnect grace on mid-call network drops, new-message notifications (tap to deep-link into the chat), connection self-heal (handshake only once the DataChannel is up — no more stuck "connecting"), and global keyboard-no-longer-covers-input. Tests: state machine / signaling / integration (Robolectric) / handshake e2e / call-history mapping — 44 JVM unit tests green; on real devices (amethyst<->chopin) two-device live voice call + ringtone + call history verified, video + lockscreen full-screen incoming still under device acceptance.
Friend P2P messaging stability — "cannot scan to add friend / messages not received / cannot connect" end-to-end fix
Message display: the receiver rewrites each message to its own perspective (peerId = sender DID, direction = incoming), fixing "message reached the DB but is invisible in the chat" (previously stored with the sender perspective and landed in the wrong conversation). Connection stability: ICE reverted to ALL (restores same-network direct host connections; the earlier relay-only attempt actually disabled direct connect and hit the TURN server own IP, making things worse) + WebRTC DataChannel open timeout 15s->40s (enough time for direct connect + DTLS handshake). Signaling-relay fallback: when the DataChannel cannot open, commands (E2EE handshake + message sync) are automatically relayed through the signaling server, so delivery no longer depends on a P2P direct connection; end-to-end encryption is unaffected (only signed/ciphertext frames are forwarded). Auto-reconnect: on connection loss the state is cleared and re-dialed within 15s (previously stale state caused fake-online-real-offline). Restart recovery: the app restores the persisted E2EE session on startup + immediate message push (no waiting for the periodic sync) + fixed the chat top loading bar spinning forever. TURN server: coturn public/private mapping fix resolves CREATE_PERMISSION 403 caused by broadcasting the private relay IP.
Personal AI knowledge base analysis pipeline de-noising (WeChat group name resolution + interests/timeline de-noise)
WeChat group topic name resolution: resolves the group display name from the contacts book instead of naming group topics with raw numeric chatroom ids. analysis.interests de-noise: filters pure-numeric/empty topic names + over-fetches before ranking, so real interests are not pushed out of the leaderboard by unresolved group ids. analysis.timeline list exclusion: timeline queries gain excludeExtraKinds, skipping app-snapshot / contact-snapshot inventory events (which carry a synthesized collection timestamp that overwhelms any reverse-chronological query); the events remain in the vault for facet counts.
PDH root memory collection: Douyin/WCDB2 hit fix + scan lifecycle hardening (pure-APK change, reuses bundle v20260617b / pdh 0.4.27)
D1 leaf-page scan: mem-scan now decides by content — memory regions containing either a file header (standard SQLCipher / WeChat) or plaintext schema CREATE TABLE (WCDB2 / Douyin decrypted-page cache) are dumped whole, then leaf-salvage --unaligned scavenges 0x0D leaf pages downstream (header-independent, covers both encryption schemes); MAX_DUMPS=30 + per-region <=64MB to avoid disk blowup / timeout. D2 scan lifecycle hardening: a finally block adds pkill "dd if=/proc" to kill orphaned dd (timeout tree-kill cannot reach the dd inside the pipe) + an AtomicBoolean single-instance lock prevents concurrent scans from repeated taps. Versions: productVersion v5.0.3.116 -> v5.0.3.117 / desktop 5.0.3-alpha.117 / Android versionCode 503117 (USR_VERSION 47 / binariesVersion 20260617b unchanged, bundle same as .116) / iOS build 117.
PDH multi-app root memory collection + source attribution + scan hardening (pdh 0.4.27 / cli 0.162.77 / cc bundle v20260617b)
Multi-app root direct collection + correct source attribution: cc hub salvage --app <key> (douyin/toutiao/wechat/kuaishou/xiaohongshu/weibo) routes messages through the new forensics/salvage-ingest.js, writing them to the vault under the right source.adapter (Toutiao → social-toutiao, no longer all lumped under douyin); the Android "one-tap root collect" button gains a target-app dropdown. Scan-engine hardening (surfaced on a real device 2026-06-17): the mem-scan script adds trap "kill 0" to reap subprocesses + wraps the collector in timeout + raises the budget 180s → 300s + a finally pkill fallback, fixing orphan root processes left behind on scan timeout. Versions: productVersion v5.0.3.115 → v5.0.3.116 / desktop 5.0.3-alpha.116 / Android versionCode 503116 · USR_VERSION 46 → 47 · binariesVersion 20260617 → 20260617b / iOS build 116.
PDH key-free forensic one-tap collection + cross-app data overview on device (pdh 0.4.26 / cli 0.162.76 / cc bundle v20260617)
cc hub salvage <dump>: the leaf-page salvager is folded into the bundleable pdh lib (forensics/leaf-salvage.js) and wrapped as a single command (dump → leaf-page salvage → social-douyin ingest), verified end-to-end on a real SQLite DB (Chinese + emoji intact). Android "one-tap root collect (Douyin memory, key-free)" button: MemSalvageCollector orchestrates a su memory scan → copy dump → cc hub salvage per dump; rooted devices only, target app must be foregrounded/logged-in, v1 limited to Douyin. Data-overview graceful degradation: when the device-bundled cc predates analysis.overview, a bare "Unknown skill" is translated into an actionable "update the on-device cc components" hint. Release chain: @chainlesschain/personal-data-hub 0.4.25 → 0.4.26 + CLI 0.162.75 → 0.162.76 published to npm; the in-APK cc bundle rolled to internal-binaries-android-v20260617 (USR_VERSION 45 → 46, binariesVersion 20260615d → 20260617). Versions: productVersion v5.0.3.114 → v5.0.3.115 / desktop 5.0.3-alpha.115 / Android versionCode 503115 · USR_VERSION 46 · binariesVersion 20260617 / iOS build 115.
PDH gov-ixiamen endpoint static-verify on a real device + Android cc bundle v20260615d (pdh 0.4.25 / cli 0.162.71)
gov-ixiamen collector host correction: the old cookie-api placeholder app.ixm.gov.cn does not exist. Running the PDH endpoint-capture runbook's static-analysis tier (read-only APK binary analysis, no login/account interaction) on a rooted device, dex analysis confirmed i-Xiamen's real backend is *.ixiamen.org.cn (gateway https://buss.ixiamen.org.cn/pbc/), now wired (overridable via opts.listUrl); the /handle/list sub-path + body stay unverified (bodies encrypted by libzxprotect, opaque to static analysis). Bank/gov findings recorded in runbook §3.1: BOC (SecNeo shell, only push-SDK hosts in plaintext) / ICBC (gateway host visible but encrypted+signed bodies) stay snapshot — a host alone is not 'verified'; 12123 host was already correct, sub-paths built natively by libNetHTProtect. @chainlesschain/personal-data-hub 0.4.24→0.4.25 + CLI 0.162.70→0.162.71 published to npm. Versions: productVersion v5.0.3.113 → v5.0.3.114 / desktop 5.0.3-alpha.114 / Android versionCode 503114 · USR_VERSION 45 · binariesVersion 20260615d / iOS build 114.
npm publish/install hardening: fix China-mirror install E404 + deprecate workflow + VS Code ext 0.28/0.29 + CLI 0.162.70
China-mirror install fix: @chainlesschain/core-infra@0.1.0 had metadata but no cached tarball on registry.npmmirror.com, so users defaulting to the Taobao mirror hit an E404 hard failure on npm install (#33). Fixed three ways — (1) manually triggered the mirror sync API to fix it live (tarball 404→200, mirror install restored); (2) npm-publish.yml now PUTs the mirror sync API after each publish (best-effort, results to job summary, never fails the publish), so every future release self-syncs; (3) README (zh+en) documents the npm i -g chainlesschain --registry https://registry.npmjs.org fallback. Added npm-deprecate.yml, a parameterized deprecate/un-deprecate workflow (uses CI NPM_TOKEN) — deprecated 0.162.68 (published from a stale tag, missing 8 PDH adapter wirings: douban/ximalaya/keep/didi/mercedes/eleme/xianyu/vipshop); 0.162.69 is the complete fix and 0.162.70 is the current npm latest. VS Code extension 0.28.0/0.29.0 (Open VSX): background-tab completion signal + chat-panel slash commands / @ autocomplete / /rewind to checkpoints. Versions: productVersion v5.0.3.112 → v5.0.3.113 / desktop 5.0.3-alpha.113 / Android versionCode 503113 · USR_VERSION 44 · binariesVersion 20260615c / iOS build 113.
Personal Data Hub adds 6 cross-platform collectors + Android cc bundle v20260615b (pdh 0.4.24 / cli 0.162.67)
New collector adapters this round: Ele.me (food-delivery orders), Xianyu (second-hand buy/sell, two-sided — counterparty role flips by side), VIP.com (flash-sale orders), Douban (book/film/music interest graph — marks become media events + items / reviews become posts / follows become contacts), Ximalaya (audiobooks & podcasts, new audio- category), Keep (multi-type workout logs). All snapshot-primary + cookie-api (injected fetch + signProvider seam, best-effort endpoints not field-verified); each adapter fully unit-tested, wired into desktop / CLI; adapter count 83 to 89. Versions: productVersion v5.0.3.111 to v5.0.3.112 / desktop 5.0.3-alpha.112 / Android versionCode 503112 · USR_VERSION 43 · binariesVersion 20260615b / iOS build 112.
Personal Data Hub collector expansion (round 2) + Android cc bundle v20260615 (pdh 0.4.23 / cli 0.162.65)
New collector adapters this round: Xigua Video (reuses _video-base, watch history + favorites), Tianyancha (monitor / search activity), Dongchedi (favorites / follows), WeChat Work PC (reuses _local-im-pc-adapter local work-IM reader, legalGate), plus gov-tax APP (scaffold, strong real-name auth, best-effort), CamScanner, Meiyou, and i-Xiamen from parallel branches. The PDH roadmap is now fully covered for consumer platforms except the 6 gov/bank strong-auth apps (individual income tax / Minsheng·BOC·BoCom banks / e-CNY / traffic-12123), which are deliberately deferred. Versions: productVersion v5.0.3.110 → v5.0.3.111 / desktop 5.0.3-alpha.111 / Android versionCode 503111 · USR_VERSION 42 · binariesVersion 20260615 / iOS build 111.
Personal Data Hub collector expansion — 13 new platform adapters (travel / shopping / social / docs / music / video / recruiting)
13 new collector adapters: Tongcheng, Didi Enterprise, Dianping, Zhihu, CSDN, WPS Docs, Tencent Docs, Baidu Netdisk, Kugou Music, iQiyi, Tencent Video, BOSS Zhipin — each dual-mode: snapshot (on-device) + cookie-api (injected fetchFn + signProvider seam, overridable endpoints). Three shared platform-family factories were extracted: _document-base (docs / cloud-drive listings) and _video-base (watch history), matching the existing shopping-base / travel-base pattern so future same-shape platforms take ~200 lines. Versions: productVersion v5.0.3.109 → v5.0.3.110 / desktop 5.0.3-alpha.110 / Android versionCode 503110 · USR_VERSION 37 · binariesVersion 20260614b / iOS build 110.
Fix: Android release APK missing cc bundle — release.yml adds downloadInternalBinaries staging + a hard verification gate
Root cause: release.yml build-android only ran assembleRelease, while downloadInternalBinaries relied solely on preBuild's lazy dependsOn, which does not fire in CI. Fix: a dedicated ./gradlew downloadInternalBinaries step before assemble ensures cc-cli.tgz lands on disk before mergeReleaseAssets snapshots it; a new hard verification gate after build (unzip-lists the APK and greps assets/local-terminal/cc-cli.tgz, exit 1 if any APK is missing it) prevents ever silently shipping a bundle-less APK again. Versions: productVersion v5.0.3.108 → v5.0.3.109 / desktop 5.0.3-alpha.109 / Android versionCode 503109 / iOS build 109 (USR_VERSION 25, binariesVersion 20260613 unchanged, bundle same as .108).
PDH Pinduoduo collection completed (user-export snapshot → cookie-api active collection) + Android cc bundle v20260613
New _syncViaCookie pulls mobile.yangkeduo transaction_list via an injected fetchFn (Node stays pure parse / orchestration, same seam as the sibling adapters). The anti_token signature is injected via the signProvider seam (pure Node cannot keep up with Pinduoduo signature rotation; the Android in-APK WebView JS VM produces it), best-effort null when no provider. orderToRecord maps fields with snake / camel dual compatibility + fen→yuan + numeric / textual status mapping; pagination stops early at the watermark. capabilities upgraded to sync:cookie-api, version 0.1.0 → 0.2.0. PDH full suite 128 files, 2094 tests pass. Release chain: @chainlesschain/personal-data-hub 0.4.5 → 0.4.6 + CLI 0.162.47 → 0.162.48 on npm; Android in-APK cc bundle refreshed to internal-binaries-android-v20260613 + USR_VERSION 24 → 25. Versions: productVersion v5.0.3.107 → v5.0.3.108 / desktop 5.0.3-alpha.108 / Android versionCode 503108 / iOS build 108.
PDH FAMILY-23 family-guard collectors v0.2 live fetchers wrapped up (Zuoyebang / Huawei Learning / Alipay)
Zuoyebang edu-zuoyebang: ZYBUSS session cookie → study / search-question records; Huawei Learning edu-huawei-learning: Huawei account cookie → course study records; Alipay finance-alipay: session cookie → mobilegw bills / transaction details (signProvider signing seam + fen→yuan + income/expense direction inference, high-sensitivity gate unchanged). All three add sync:cookie + _syncViaLive (emit snapshot-shaped events, normalize path unchanged) + a shared _live-json-helpers. Endpoints follow each platform's common web shape + multi-field-name tolerance (best-effort, not field-verified against a real session). +39 tests, PDH full suite 128 files, 2083 tests green. This release also ships the cc CLI 0.162.41 Claude-Code parity work that was published to npm earlier (project memory cc.md hierarchy + REPL steering + structured output --json-schema + cc mcp serve). Versions: productVersion v5.0.3.106 → v5.0.3.107 / Android versionCode 503107 / iOS build 107.
PDH Kuaishou api_ph base64 collection fix + Amap trip-title bug + travel / social adapter test wrap-up (all 55 repo adapters at 100%)
Fixes Kuaishou kuaishou.web.cp.api_ph profile collection failing after the cookie changed to base64(JSON) (apiPhDecodeCandidates decode chain, pdh 0.4.4); fixes travel-base buildTitle not recognizing the name field, which left Amap route / search event titles missing (caught red-then-green); corrects 3 stale comments in the Toutiao / Kuaishou / email adapters. Test matrix wrap-up +180: Xiaohongshu ADB trio 58 + travel 6 modules from scratch 74 + whatsapp / shopping-base 24 + Kuaishou base64 9 — all 55 repo adapters at 100% test coverage. pdh 0.4.3 → 0.4.4 + CLI 0.162.39 → 0.162.40 on npm; Android in-APK cc bundle rebuilt to internal-binaries-android-v20260611 + USR_VERSION 21 → 22. Real-device (Xiaomi amethyst) proof: installing the new APK triggers LocalFilesystemBootstrapper sentinel 17→22 re-extraction, with pdh=0.4.4 + both fixes grep-confirmed on device. Versions: productVersion v5.0.3.105 → v5.0.3.106 / Android versionCode 503106 / iOS build 106.
cc agent MCP prompts / resources + SubagentStop hook + --fork-session (CLI 0.162.38) + Android in-app cc bundle refresh
MCP prompts as slash commands + MCP resources exposed to agent / REPL; SubagentStop settings.json hook (Claude-Code parity); cc agent --fork-session clones an existing session into a new branch to continue; CLI 0.162.38 on npm. Android in-APK cc bundle rebuilt to internal-binaries-android-v20260610 (cli 0.162.38 + pdh 0.4.3) + USR_VERSION 20 → 21 (v5.0.3.101's USR_VERSION 20 had spun idle because the bundle was not rebuilt; this release closes the loop). CLI e2e shared helper (testHome + freePort) + e2e isolation / retry CI hardening. docs-site adds 14 CLI command user docs + a site-wide number reconciliation (155 commands / 145 skills / 25 Android). Versions: productVersion v5.0.3.104 → v5.0.3.105 / Android versionCode 503105 / iOS build 105.
CLI 0.162.37 (IDE bridge finalization) + all-platform version alignment + docs / branding cleanup
CLI 0.162.37 on npm (aggregate of the finalized IDE bridge phases); iOS / Android / desktop aligned to v5.0.3.104; VS Code extension Open VSX auto-publish CI + an icon redraw trio; JetBrains buildPlugin fix (instrumentation disabled); docs-site adds 8 CLI user-doc pages (cc goal / cost / checkpoint / command / statusline / mcp OAuth / web_search / run_shell background) + a Family Guard user page + a V2 governance command developer reference; release-doc redaction (personal signer info cleanup); desktop vitest-4 stub bug + 12 stale test fixes. Versions: productVersion v5.0.3.103 → v5.0.3.104 / desktop 5.0.3-alpha.104 / CLI 0.162.36 → 0.162.37 / Android versionCode 503104 / iOS build 104.
cc loop (/loop parity) + IDE bridge Phase 3/4 (JetBrains parity + release pipeline) + VS Code extension visualization & branding
cc loop mirrors Claude-Code's /loop: repeatedly run a prompt or slash command on a fixed interval, with --dynamic self-pacing (including prompt-mode agent flag pass-through), --save/--resume session persistence, and stable operation in headless (non-TTY) environments. IDE bridge Phase 3 brings JetBrains to parity (a pure-JDK protocol core + IntelliJ glue, CLI zero-change double proof + a live cross-language interop run), and REPL IDE auto-connect now honors --ide/--no-ide; Phase 4 lands the release & maintenance pipeline ide-extensions.yml (vsce package/publish + gradlew build/publish plugin, tag + secret double-gated, no GitHub Release, fail-fast on missing secret). The VS Code extension adds IDE bridge visualization (status bar + sidebar + dashboard, 0.2.0) and ships the ChainlessChain brand logo as the extension & Activity Bar icon (0.2.1). Versions: productVersion v5.0.3.102 → v5.0.3.103 / desktop 5.0.3-alpha.103 / CLI stays at 0.162.36 / personal-data-hub 0.4.3 unchanged / Android versionCode 503103 / iOS build 103.
IDE bridge (cc ide + VS Code extension) + cc CLI Claude-Code parity wrap-up + cc agent --image vision input
cc agent gains MCP OAuth remote authorization, custom + built-in context-usage status line, output styles (named personas), pluggable web_search, extended thinking (--think/--ultrathink), settings.json full-event hooks (PreToolUse real blocking / UserPromptSubmit / SessionStart / Stop / PreCompact with block semantics), headless `agent -p`, `/compact` auto-compaction, dual-engine checkpoint, and permission rules (allow/ask/deny), plus `cc agent --image` multimodal vision input. Versions: productVersion v5.0.3.101 → v5.0.3.102 / desktop 5.0.3-alpha.102 / CLI 0.162.35 → 0.162.36 on npm / Android versionCode 503102 / iOS build 102. (Note: the Android in-app cc bundle still ships the prior code pending a cc-cli.tgz rebuild, same as last release.)
CLI reaches Claude-Code parity + PDH one-click WeChat 4.0 / QQ-NT collection + security fail-closed bundle
PDH gains full WeChat 4.0 collection (per-DB keys + zstd message decompression + official accounts / Moments / favorites + humanizing non-text messages such as links/files/images) and one-click QQ-NT decryption + parsing: verified end-to-end on a real nt_msg.db, restoring uin → friend nickname and group code → group name. On security, a batch of fail-closed closures: SAML signature, OAuth id_token, channel message signing, and permission-ipc DB fallback all fail closed, with hardcoded passphrases removed. Also landed: a U-Key passphrase escrow layer (default off) and V6-shell wiring for the desktop DB / LLM performance panels. Version surfaces: productVersion v5.0.3.100 → v5.0.3.101 / desktop 5.0.3-alpha.101 / CLI 0.162.31 → 0.162.32 / personal-data-hub npm package 0.4.2 → 0.4.3 / Android versionCode 503101 · USR_VERSION 19 → 20 / iOS build 101.
Personal Data Hub collection major update + real-device live — one-click ingest from many local sources + database at-rest encryption on by default
Email bills are auto-filled by the LLM when structured fields are missing, and iOS encrypted backups can now be decrypted and imported. On the security side, database at-rest encryption is now ON by default (encrypted on disk, automated gates all green), and the DID private key on packaged builds now fails closed (refuse to continue if the key is unavailable) rather than silently falling back to plaintext. Android "AI study companion" wires reward points, a parent-gentleness monthly report, and child tasks into tappable Family-tab entries: a parent assigns homework → the child enters guided mode (the AI does not hand over answers) → submit → grade → redeem points; companion chat is encrypted to disk via the device secure element, so even a parent export only sees ciphertext. Engineering: ~4000 lines of dead code removed, 7 unused dependencies dropped, URL/path validation added before system open-external/open-path, and several "false-green" CI gates fixed. Version surfaces: productVersion v5.0.3.98 → v5.0.3.99 / desktop 5.0.3-alpha.99 / CLI 0.162.29 / personal-data-hub npm package 0.4.0 / Android versionCode 503099.
Social / home ANR fix (main-thread keystore moved to IO) + Family Guard "AI study companion" Epic A–G pure-logic layer complete + PDH analysis-engine intent routing
About 150 commits accumulated on top of .97 ship together here: Family Guard / AI study companion Epic A scaffolding → B unbind & pairing → C telemetry uplink → D mobile↔mobile calling → E SOS → F geofencing → G multi-guardian negotiation + TimeAuthority clock-tamper defense — the entire pure-logic layer (unit-testable, zero-device) is mined out across all 7 epics (:feature-family-guard 337 tests green). PDH AnalysisEngine intent routing closed out (sum-amount now splits per-currency instead of summing across currencies / count hard-caps the illustrative sample) + static security audit F2–F6 (PII redaction / cookie fail-fast / WebView bridge scoping). Browser-extension background.js Phase 0/1 split: cookies / storage / network / page / devtools / performance handlers all modularized. Desktop adds ~80 new Pinia store unit-test suites. Version surfaces: productVersion v5.0.3.97 → v5.0.3.98 / desktop 5.0.3-alpha.97 → .98 / CLI 0.162.27 → 0.162.28 (version-only bump, no src change). All 17 platform artifacts (Win / Mac / Linux / Android / iOS) shipped; desktop auto-update version comparison verified.
Android cloud LLM route now reads from local RAG + contact phone numbers visible to AI + 6-platform endpoint hotfix bundle
6-platform endpoint hotfix bundle: Xhs 3 endpoint path/param sync to real JsBridge routes (/api/sns/web/v1/me → /v2/user/me etc.) + Toutiao extractUid adds uid_tt / sso_uid_tt / tt_webid fallback to fix passport_uid being null and rejecting login + Weibo /api/favorites upstream removed → graceful skip instead of fake 404 + Douyin favorites pagination has_more loop fetches the full set (previously only first page ~24/N silently dropped) + Android askQuestion timeout 60s → 240s (covers MediaPipe cold-start over budget so first ask is not silent) + cc hub aichat-health timers all unref so commands exit immediately (previously held event loop). Engineering docs: handbook adds trap #27 (USR_VERSION sentinel cache miss after PDH/CLI lib refresh — must bump Android USR_VERSION when editing pdh/lib or cli/lib, otherwise real device hits fast-path and skips extraction, runs old code) + trap #28 (workspace dep npm publish stale — must bump package version + npm publish + USR_VERSION when editing pdh/lib or cli/lib, otherwise cc-cli.tgz ships stale code). Version surfaces: productVersion v5.0.3.96 → v5.0.3.97 / CLI 0.162.26 → 0.162.27 / @chainlesschain/personal-data-hub 0.3.7 → 0.3.9 / Android versionCode 503097 / USR_VERSION 12→17 (5 cumulative bumps to force re-extraction) / iOS CFBundleVersion 97.
Desktop check-for-updates safety net — release-in-progress friendly toast + system notification fallback when window is hidden
New desktop-app-vue/src/main/system/update-error-classifier.js classifies electron-updater errors by kind: release-in-progress (Cannot find latest*.yml / 404 fetching latest*.yml) vs generic. auto-updater.js error handler routes by kind: release-in-progress is silent during background checks; manual checks pop an info dialog "New release is publishing, please try again in a few minutes" instead of dumping a stacktrace. enhanced-tray-manager.js#triggerCheckForUpdates calls showWindow() before triggering the check so the main window is in front. auto-updater.js on update-downloaded + update-not-available adds OS Notification fallback (when window is hidden / minimized / destroyed); clicking the notification brings the window forward → user immediately sees the notifier card / native dialog. New update-window-visibility.js extracts shouldFallbackToOsNotification as a pure helper. 17 unit test cases cover both halves (8 error-classifier including real v5.0.3.95 error text + latest-mac/linux variants + 404-only-on-non-yml counterexample + null/undefined edges; 9 window visibility cases including null / destroyed / unsupported / visible / hidden / minimized / defensive compat).
legacy-GPU Chromium 130+ crash auto-recovery (trap #26) — "installer crashes" report turned out to be 0xc0000602 GPU process fail-fast
Fix: marker-file auto-recovery. desktop-app-vue/src/main/index.js setupApp() writes a .launching marker to userData before startup; mainWindow.once("ready-to-show") clears it. Next launch finds the leftover marker → assumes last run crashed → persists .gpu-disabled file + app.disableHardwareAcceleration() + Chromium switches (--disable-gpu / --disable-gpu-compositing / --disable-software-rasterizer). Supports CHAINLESSCHAIN_DISABLE_GPU=1 env var for manual trigger; deleting <userData>/.gpu-disabled restores GPU. Same disable-gpu recovery model as VS Code / Slack / Cursor / Discord — external-behavior-driven, does not depend on any GPU API state.
PDH social dual-channel buildout — Kuaishou as 4th PC-ADB C-path platform + Toutiao/Bilibili/Weibo/Xhs Mode B in-APK root collectors + Bridge dry-run doctor catches SDK rotations 5-10 days early
Xhs / Douyin in-WebView prefetch ported from the Bilibili architecture (hidden WebView runs the platform-native signing JS + JavascriptInterface bridges results back to Kotlin which writes staging JSON). Xhs v6 added cookie cross-subdomain bridge + v8 raised isLoginSuccessByCookie threshold 20 → 50 to reject visitor tracking sessions + v13 id_token httpOnly cookie decode + profile event push. All 5 social login flows switched to Mobile Chrome UA + Douyin gains cookie-presence detection (reverting the wrong v5.0.3.84 direction). Android release engineering: R8 minify moved to systemProp prefix to resolve the v5.0.3.89 ConcurrentModificationException regression; v5.0.3.91 disables R8 outright as the safety net. Repo hygiene: gitee removed from .husky/post-commit auto-push chain (local .git is 1325MB > gitee 1GB quota, every commit was failing and stacking WARN lines); the orphan-snapshot script remains as an emergency rebuild path. Six design docs published together: PDH_Kuaishou_C_Path_Real_Device_E2E + PDH_Toutiao_C_Path_Real_Device_E2E + PDH_Bilibili_Mode_B_Real_Device_E2E + PDH_Weibo_DB_Schema_Probe + PDH_Weibo_Mode_B_Real_Device_E2E + PDH_Mode_B_Toutiao_Douyin_Real_Device_E2E — all Win-first 6-scenario template. Outstanding: Toutiao / Bilibili / Weibo / Xhs Mode B real-device root + magisk + frida-server runs (cannot be done on the Win dev box — needs Mac/Linux + a rooted device). Version surfaces: productVersion v5.0.3.85 → v5.0.3.91.
Android MediaPipe on-device LLM real-wiring + 4-route unified LLM selector + Personal Data Hub Vault Browser (desktop + Android data visualization)
149 tests green (36 categories + 13 vault helpers + 27 FTS5 native integration via sandbox runner + 4 composable + 10 store + 12 view + 19 desktop renderer + 11 export + 10 android renderer + 7 android VM). PDH partial-index drift recovery: migration v4 explicit DROP+CREATE on 4 tables — all partial unique indexes now carry WHERE source_original_id IS NOT NULL — fixes trap #23 where CREATE UNIQUE INDEX IF NOT EXISTS hid the schema drift so adapter.sync silently failed (events table stuck at 0 rows while raw_events accumulated 1308 — the golden symptom). New cc hub rederive [--adapter <name>] [--batch-size <n>] salvages orphan rows in legacy vaults without re-fetching the source. PDH §2.5 travel adds 12306 (5 cards) + content platforms Toutiao / Kuaishou v0.1 placeholder cards + QQ HubLocal UI wire to Phase 13.5 v0.2 collector (already landed) plus 11 ViewModel unit tests. PDH social MockWebServer integration tests filled the 0-coverage layer: 4 platforms / 33 cases (Bilibili 7 + Weibo 9 + Xiaohongshu 11 + Douyin 6) covering HTTP 412/401/461/500 propagation, anti-bot login redirects, X-S / X-T signing header gates, buvid3 substitution, containerid magic prefix. Bilibili WBI signature fix for the silent {code:0,data:list:[]} response. Android Bootstrap @Singleton race fix → companion-object Mutex + self-healing mkdirs (trap #24). Version surfaces: productVersion v5.0.3.84 → v5.0.3.85 / CLI 0.162.17 → 0.162.18 / npm @chainlesschain/personal-data-hub 0.2.4.
Seven on-device developer-activity adapters landed — your local workflow IS your personal RAG corpus
All 7 adapters route into the category=system bucket so they are individually filterable in the Vault Browser sidebar; FTS5 trigram CJK full-text search works the same way (searching "react" matches git commit messages AND npm install lines from shell history AND vscode workspace paths). This matters most for developers: your 8-hours-a-day keyboard workflow — which repo on which branch doing what / what was open in vscode / what you Googled / which zip you dragged from Downloads — all flow into the vault, so when the AI is asked "what was I debugging last Wednesday?" it can correlate git checkout logs + vscode workspace + browser stackoverflow history + shell commands all at once. A single data source can never answer that. Companion fix: bs3mc / bs3 ABI dual-load (trap #23) — fixes Electron 39 (ABI 140) vs Node 22 (ABI 127) where any SQLite reader (chrome-db-reader / vscode-reader / etc.) would crash native binding on one of the two paths. All readers now dual-load with a new Database(":memory:") smoke test.
Personal Data Hub v0.2 burst — 11 placeholder cards wired + WeChat / QQ real-capture + Android on-device LLM scaffold
Three locks UI + real wiring: reject cloud / destroy / export (cc hub export wired through). AI citation chip → cc hub event-detail links back to the raw event. release.yml split publish-deps into a pre-job to break the v5.0.3.79 desktop build chicken-and-egg. Test baseline: 93 new snapshot tests (weibo 8 + douyin 8 + xhs 8 + toutiao 8 + kuaishou 8 + jd 8 + meituan 8 + pinduoduo 8 + baidu-map 8 + tencent-map 8 + qq 13) + WeChat Phase 12.10 51 new unit tests (CredentialsStore 14 + DbExtractor 17 + FridaInjector 15 + LocalCollector 10) + QQ Phase 13.5 27 Kotlin unit tests. 3 stale-assertion fixes same day: longtail Douyin uid (constructor went dual-mode optional) + analysis TOTALS regex case (/i flag) + hub-command snapshot (event-detail / export missing from pin list). Version surfaces: productVersion v5.0.3.78 → v5.0.3.80 / CLI 0.162.14 → 0.162.16 / npm @chainlesschain/personal-data-hub 0.2.1 → 0.2.3 / Android versionCode 503080 / iOS CFBundleVersion 80.
Personal Data Hub Plan A v0.1 — Android local data hub snapshot mode, real-device closure
Three real-device hardening fixes: originalId required (adapter yield must carry the field or invalidCount=rawCount false-success + a 1305-row audit burst) + skip-embeddings flag (Plan A mode does not need vectors) + audit pagination splits 1305 → 50/page. Android cc subprocess W^X execve via mksh symlink + reader-thread try/catch(Throwable) for EOF race + ingestSystemDataAndroid timeout 30s→120s. The 7 E2EE androidTest cases were reactivated via X3DHSimulator state-less E2EESession factories. bootstrap LLMManager is now registered as a singleton + web-shell PDH wiring injects CcLLMAdapter so web-shell honors the active LLM provider. AnalysisEngine reads persons + items, not just events, to stop hallucinated contact counts + LLM ResponseCache bypass for analysis ask (no more stale-cache answers). 6 real-device traps closed; engineering foundation 100% verified; feature layer ~7-9d remaining. v5.0.3.77 shipped the iOS .ipa real-device build alongside.
WeChat Phase 12.6.7-10 — bootstrap orchestration + IPC/WS + cc hub wechat CLI + Vue UI wizard
Total this session: 1223 tests across 67 files (1068 hub package + 183 desktop + 46 CLI + 18 web-panel — composable / VM / IPC / WS / wiring / store / accounts JSON / privileged whitelist / integration end-to-end). Memory captured: wechat_bootstrap_orchestration_layer.md — the pattern of adding a bootstrap.js when N component sub-phases produce parts but 3 callers (IPC, WS, CLI) each have to wire them. Also corrected a stale docs-site claim: iOS Phase 14.2 UI scaffold was actually fully landed at 3db7b5a73 (650 LOC PersonalDataHubViews.swift + 3 ViewModels + RemoteDependencies + 1491 LOC of tests), not lost-to-race as previously noted. Remaining: Phase 12.9 rooted-Android real-device E2E and Phase 14.4 mobile real-device E2E both gated on physical hardware.
Personal Data Hub 13-phase burst — 8/8 AIChat real-vendor wired + 7 social adapters + .72 iOS keychain hotfix repackage
v5.0.3.72 is also a release-pipeline retrospective. v5.0.3.71 had all 5 desktop builds fail with EUSAGE — root package-lock.json out of sync with packages/personal-data-hub/package.json: during the Phase 12/13 burst the hub added adm-zip@^0.5.16 (iTunes encrypted backup zip) + iconv-lite@^0.6.3 (GBK-encoded social history) optional deps; workspace package.json declared them but root package-lock never synced, so all desktop installers hit EUSAGE at the electron-builder step. 5d8ba08b5 fix(deps) synced root lock, then .72 was repackaged with the same iOS keychain Logger.swift NSLock concurrency fix (commit 625e86819, forward from .70) and shipped 18 assets complete. d03c87d0a follow-up bumped packages/cli in root lock to 0.162.7 closing the loop. Version surfaces: CLI 0.162.5→0.162.8 / productVersion v5.0.3.70→v5.0.3.72 (skipping .71) / desktop-app-vue 5.0.3-alpha.70→.72 / iOS CFBundleVersion 70→72 / Android versionCode 503070→503072. The actual released artifact is .72; .71 does not exist in GitHub Release list, but lib/adapters code is on main and npm chainlesschain@0.162.7 is published — only desktop installers ride .72.
iOS .ipa reship + Android cc CLI bundle wired (v5.0.3.65/66 one-evening double-patch)
v5.0.3.66 in essence is a release-flow engineering retrospective — a reship of v5.0.3.65. Root: v5.0.3.65 build-ios failed because Phase 6 new views were not wired into Xcode; desktop + Android + npm all green but .ipa missing. GitHub release model is immutable-releases once published, so .ipa can no longer be patched onto v5.0.3.65 — must cut a new version. Repair chain: (1) inspect build-ios job log to find 9 "cannot find X in scope" errors (UpdateBannerOverlay + 8 Phase 6 views referenced from RemoteOperateView) → verify files on disk but not in pbxproj; (2) extend wire_app_sources.rb FILES with 13 .swift paths + ios-wire-app-sources.yml workflow_dispatch (dry_run=false) lets ruby xcodeproj gem rewrite pbxproj on a macOS runner and push back to main (commit 2fe98ef9f); (3) bump 4 enforced surfaces (productVersion / desktop-app-vue version / ios CFBundleVersion / android versionCode+versionName) + tag v5.0.3.66 + push; (4) release.yml goes 11/11 green, build-ios 5min11s produces .ipa, create-release / publish-cli / finalize-release all pass, 18 assets in final release. cli-tests and publish-cli skip because 0.162.2 already published — keeps npm latest dist-tag clean. Android cc CLI bundle in v5.0.3.65: the full 41MB chainlesschain CLI npm package (with Node 22 runtime) is dropped into Android APK assets/local-terminal/, wrapper shell scripts route around the unusable #!/usr/bin/env node shebang trap, Termux libc++_shared.so is renamed libtermux_cxx.so for AGP 8 stripping compat, the cc CLI wrapper's own shebang switches from /system/bin/sh to prefix/bin/mksh — Android W^X puts /system/bin/sh under shell_exec SELinux domain which untrusted_app (pty domain) cannot execve, while prefix/bin/mksh actually points to ../lib/libmksh.so → nativeLibraryDir/libmksh.so, on the Android lib/<abi>/lib*.so execve whitelist. The combo lets cc CLI run inside the Android app directly without Termux.
iOS maturity — Phase 1-6 + AI Chat closure + 4-segment version + signed .ipa shipped
v5.0.3.64 does three things and closes iOS version management: (A) Clear all stale AppConstants hardcodes — `AppConstants.App.version` was hardcoded "0.32.0" (months stale), `buildNumber` "32", `bundleId` "com.chainlesschain.ios" (actual Info.plist is com.chainlesschain.ChainlessChain — CodeSign also uses this). All migrated to dynamic Bundle.main reads via 5 new helpers (`Bundle.appShortVersion` / `appBuildNumber` / `appFullVersion` / `appFullVersionTag` / `appDisplayName`). AIDashboardView.swift hardcoded "v0.16.0" + PluginManager.swift fallback "1.7.0" all replaced. Settings About row now shows full 4-segment v5.0.3.64 + a Bundle ID row so users can confirm they have the real build. (B) Second-pass iOS 17 API audit — 596 .swift files scanned with 29 patterns (assumeIsolated / @Observable / SwiftData / symbolEffect / ContentUnavailableView / scrollPosition / KeyframeAnimator / visualEffect / sensoryFeedback / Previewable / dialogSeverity / SubscriptionStoreView etc.) — 0 new violations. AppState.swift:94-118 v5.0.3.63 fix in place (Task { @MainActor in ... }); SystemInfoView.swift:65-73 .symbolEffect inside #available(iOS 17, *) with iOS 16 static fallback; ImagePickerView.swift @Previewable inside @available(iOS 17, *) #Preview {} — preview-only never ships. (C) Three-layer regression coverage — BundleVersionTests.swift 11 unit (helpers + AppConstants dynamic semantics); AppStateNotificationTests.swift 7 integration (databaseUnlocked / didAuthenticated post does not crash + repeated post stability + 4-segment version lock); ChainlessChainUITests testSettingsVersionDisplaysFourSegmentTag + testPINUnlockDoesNotCrashOnFirstLaunch XCUITest real-device regression. Same period iOS Phase 5 AI Chat static audit found 4 real bugs: (1) finalizeStreamingPlaceholder empty-string nil-coalesce bypass — old code `messageId ?? oldMsg.id` but ChatStreamEnd.parseFromEnvelope fills "" (not nil) when server lacks messageId; nil-coalesce does not catch "", which overwrites the local-assistant-<UUID> placeholder id; SwiftUI ForEach(messages, id: \.id) identity collapses (multiple rows share empty id). Fix: explicit guard `if let mid = messageId, !mid.isEmpty`. (2) deleteConversation partial rollback — failure to delete current conversation only restored the list; currentConversation / messages stayed empty. New rollbackDelete + wasCurrent / originalCurrent / originalMessages snapshot enables atomic full rollback. (3) sendMessage missing defensive stream-in-flight guard — UI switches to cancel button while streaming, but VM cannot assume the upper layer disabled send (programmatic call / double-tap race / upper bug can bypass). Added `guard currentStreamId == nil` before the DC gate. (4) selectConversation stale streamId pollution — switching conversations did not clear currentStreamId; edge case where the new conversation's last row was a streaming placeholder (previously never finalized) — prev stream's delta would mutate the new conv's last. Fix: explicit currentStreamId = nil + isStreamingMessage = false. + 4 integration tests (Phase5AIChatIntegrationTests) cover events fan-out / cancel ordering (discardStream → local state settled → cancelStream RPC sent → late chunk silently dropped) / offline drain (DC down → ai.createConversation queues → DC ready edge → drainer triggers) / multi-conversation stream isolation (conv A streams → switch to conv B → sA later delta+end never touches conv B messages). iOS Phase 6 sprint one night 19 commits: desktop knowledge-handler.js +30 method (folders 5 + tags 3 + alias 1 + versions 4 + star/pin 6 + archive 3 + import-export 4 + advanced tags 3) + ai-handler.js +25 method (Conversations advanced 5 + Prompt templates 3 + RAG 5 + Multimodal 4 + Code helpers 4 + Agents 4); iOS KnowledgeCommands actor wraps 31 method (30 desktop + getNote alias) + AIExtendedCommands actor wraps 25 method; KnowledgeView + AIExtendedView SwiftUI + 2 VM + 2 new main tab (→ 15 total); Multimodal v0.3 live recording AVAudioRecorder 16kHz mono AAC + Agents 2 new sub-tab + 5 tab horizontal picker + Agent streaming desktop runAgentStream + iOS poll loop + Agents UI live. Green baseline 1fb947b32, iOS CI real-compile verified (the only Swift compile path available on Win).
Android remote file skill wired — browse / upload / download PC files, one-tap open inside the app
Productization closure for Plan C Android↔PC file transfer. FileTransferScreen now exposes 5 TopBar icons: Browse remote (input ~ / C:/Users/... → enter, directories first alphabetical, tap directory recursive, tap file downloads, ↑ parent / refresh) / Upload (system GetContent picker → auto chunk upload → Snackbar shows "PC: C:/Users/longfa/Downloads/<name>" + "Copy path" button, PC auto-appends (1)/(2) suffix anti-collision) / Manual download (input remote path + filename) / Local downloads folder (v5.0.3.57 new — MediaStore.Downloads.EXTERNAL_CONTENT_URI query of public Downloads, DATE_ADDED DESC sorted, each row shows filename/size/time + "Open" launches system viewer) / Clean up history older than 30 days. PC side desktop-app-vue/src/main/remote/handlers/android-file-handler.js newly written 460 lines, dispatches 11 actions (listDirectory/getFileInfo/exists/delete/createDirectory/requestUpload/uploadChunk/completeUpload/requestDownload/downloadChunk/cancelTransfer/listTransfers), fields aligned with Android FileCommands.kt (type not isDirectory / modifiedTime not modifiedAt / entries not items). 6 interlocking bugs fixed: (1) P2PClient.kt:538-542 chainlesschain:* skip guard too wide — old code shadowed P2PClient.sendCommand own responses, pendingRequests never completed. Fix: narrow to skip only chainlesschain:command:request. (2) Plan C path P2PClient.connectionState always DISCONNECTED — RemoteOperateScreen → signaling forward never called P2PClient.connect(), all RemoteCommandClient invocations failed immediately. Fix: RemoteCommandClient.invokeTyped delegates to SignalingRpcClient.invoke(pcPeerId), pcPeerId from PairedDesktopsStore.devices.firstOrNull(). (3) PC handleFileCommand was a thin stub — old switch only had case "list" (SQL table) + case "requestUpload" (dialog.showOpenDialog showed a PC-side folder picker, completely wrong UX). Fix: replace switch with delegate to new android-file-handler. (4) FileTransferHandler (remote-gateway registered) sandboxed in userData + field mismatch — _resolvePath forces prefix app.getPath("userData"), C:\Users\... always Access denied. Fix: do not reuse, write dedicated handler with no sandbox (trusted paired peer). (5) Checksum algorithm mismatch → repository auto-deletes downloaded file — first cut returned "sha256-prefix:abc...", but FileTransferRepository.kt:264-276 expected "md5:" + full MD5, mismatch immediately deletes local file + marks FAILED + throws Checksum mismatch. Fix: return checksum:null to skip Repository verification. (6) getExternalFilesDir(null) hides downloads — /sdcard/Android/data/.../files/downloads/ under Android 13+ scoped storage takes 5 taps + "show hidden" to reach. Fix: API 29+ uses MediaStore.Downloads.EXTERNAL_CONTENT_URI insert to write public Downloads, returns content:// URI ready for Intent.ACTION_VIEW, no WRITE_EXTERNAL_STORAGE permission needed. 34 new unit tests — PC vitest 30 cases (_resolvePath × 5 / listDirectory × 5 / getFileInfo + exists × 3 / createDirectory + delete × 3 / Upload roundtrip × 5 incl collision + metadata.targetDir / Download roundtrip × 3 incl Bug 5 regression checksum-must-be-null / cancelTransfer × 2 / handle() dispatch × 2 / listTransfers × 1) + Android RemoteCommandClientTest 4 cases (delegate to SignalingRpc + Bug 1+2 lockdown coVerify(exactly=0) does-not-touch p2pClient.sendCommand). Xiaomi 24115RA8EC × Win desktop real-device E2E 8 scenarios all pass: E1 browse home / E2 browse root / E3 enter sub-directory / E4 small file upload + copy path / E5 collision (1) suffix / E6 small file download / E7 "Open" launches viewer / E8 local downloads panel lists everything. Design doc docs/design/Android_Remote_File_Skill.md / user doc docs-site/docs/guide/remote-file.md. Known limits: large files >10MB through signaling 4-hop base64 chunks may time out — will switch to DC after Plan A.1 stabilizes; API <29 MediaStore.Downloads unavailable, fallback to app-private path which users cannot find — add FileProvider later if reported; destructive actions (delete / writeFile) currently have no approval gate, trusted paired peer executes automatically — future mobileApprovalChannel layer.
iOS port — Phase 1+2+3+4 framework complete (desktop pairing + remote terminal + remote-operate framework + 4 typed skills + Notification skill)
v5.0.3.55 mirrors 1+ year of accumulated Android mobile capabilities (QR pairing / remote terminal / remote-operate framework / Notification skill) onto iOS. All 4 phases are framework-complete ports. Phase 1 desktop pairing three flows commit c30b415a8 (71 unit tests, Modules/CoreP2P/Pairing 9 swift + Features/Pairing 8 swift + PairingSignalingGate interface + PairedDesktopsStore UserDefaults JSON persistence + desktop follow-up manual-pair-listener.js 220 LOC pairing-code alias listener). Phase 2 remote desktop terminal commit 7613ea710 (163 unit tests, Modules/CoreP2P/RemoteTerminal 13 swift + Features/RemoteTerminal 6 swift + 4 xterm.js bundle resources + SignalClient.forwardedMessages multi-subscribe AsyncStream backfilling Phase 1 design gap). Phase 3 remote-operate framework + 4 typed skills commit 759a1e907 (~264 unit tests, Modules/CoreP2P/RemoteSkills 16 swift + Features/RemoteOperate 6 swift + RemoteCommandClient single-consumer fix moves webRTCClient.inboundMessages subscription owner to commandClient, TerminalRpcClient now subscribes to commandClient.events to avoid AsyncStream single-consumer event split bug). Phase 4 Notification skill commits 45b485fdd → 5877b5d84 6 sub-phases all landed (41 new unit tests cumulative ~313, 3 swift CoreP2P + ViewModel 322 LOC + View 517 LOC + existing PushNotificationManager unchanged / only 1-line conformance extension + DI events fan-out task fixing the cmdClient.events AsyncStream single-consumer multi-skill subscription trap + RemoteOperateView 6th tab + SkillTabPickerView REWRITE horizontal scroll + Capsule unread badge per design §7.9 option B). 2 P0 fixes: RemoteCommandClient.invoke withThrowingTaskGroup timeout path pendingResponses leak + RemoteWebRTCClient.waitForAnswer pendingAnswer not cleared cleanly — 2 regression tests + 1 integration test verify pools clean. 4 design docs + 4 trap memories (ios_qr_pairing_three_flows / ios_remote_terminal_phase2 / ios_remote_operate_phase3 / ios_remote_notification_phase4) + feedback_ios_ui_mirrors_validated_android (UI info architecture must mirror Android Kt screens already real-device E2E validated, HIG deviation limited to 6-item whitelist). Same batch: #21 P1 main scope 5/5 — A.1 Linux native pairing (cc pair preflight 5-item LAN diagnostics + cc pair token subcommand group + systemd hardening template + 9-section docs/linux/PAIRING.md, 57 unit tests) + A.2 three-platform UI consistency design doc (4 must-match + 4 must-differ) + B.1 web-shell private-key signing UI (MultisigSigner + in-process WS topic bypassing 6-10s cold start + SignProposalModal + unified-key-manager DID routing, 113 unit tests) + B.5 cross-chain bridge outbound × m-of-n multisig Layer 1+2 across 8 PRs (CLI + cc_bridges provenance columns + crosschain-mtc helpers + verifyMultiHopBridgeEnvelope auto-runs check) + C.1 watch face VoiceMode shortcut (phone NavGraph + wear MessageClient forward + trigger_source locked to WEAR_FORWARD anti-spoof, 33 unit tests).
Plan A.1 Remote Terminal Android↔Desktop WebRTC DataChannel direct (Phase 1-5 landed in one day, 7 commits)
v5.0.3.52 Plan A real-device validation on Xiaomi 24115RA8EC × Win desktop dev surfaced one architectural issue: a 4-hop signaling chain phone→router→public-relay→desktop-RelayClient is fragile under NAT idle / cellular carrier-side TCP RST — any hop down kills the whole chain. Plan A.1 moves high-frequency / high-throughput terminal traffic from the signaling chain onto a WebRTC DataChannel direct connection, bypassing every middle hop; signaling stays as a fallback. Perf targets: end-to-end RTT p50 200-500ms → 30-80ms LAN / 50-200ms TURN, p99 1.5-30s with timeouts → 200-800ms, sustained-connection stability 20s-2min outages → hours-long (depends on ICE keepalive). Phase 1 Trap 1 fix commits d22b7ac8a + bb759bc78: SignalClient.forwardedMessages migrated to multi-subscribe SharedFlow replacing the single-listener setOnForwardedMessageReceived — original bug: the ice:config interceptor installed by WebRTCClient.initialize was silently overwritten when the user entered TerminalListScreen and TerminalRpcClient.start set its own listener → ice:config pushes dropped → iceServers expired in 24h → cross-NAT became unreachable; added WebRTCClient.dataChannelReady StateFlow Boolean derived flag where READY truly means DC OPEN (avoiding ICE-connected-but-DC-not-open false positives). Phase 2 commit a01eeac47: SignalingRpcClient.invoke now embeds a transport selector connectionState==READY && preferDataChannel → webRTCClient.sendMessage (DC), throws or not-ready → fallback signaling, two listeners simultaneously consume signalClient.forwardedMessages + webRTCClient.messages, same requestId → same CompletableDeferred (second complete is a no-op; dual delivery is safe without explicit dedup), all RPC clients (TerminalRpc + system.* + ai.*) share one chokepoint. Phase 3 commit 91e77e489: TerminalListViewModel.init detects DC not-ready and async-triggers RemoteConnectionManager.connect + UI chip shows P2P direct (green) vs Relay path (yellow) so the path state is user-visible. Phase 4 commit dd9b1227e Android + fc3752360 desktop: Android TerminalRpcClient subscribes BOTH signaling + DC SharedFlow, dedups stdout by (sessionId|seq) with a 256-entry LRU / exit by sessionId with 64-entry; desktop mobile-bridge.bridgeToLibp2p gains 128-entry / 30s-TTL LRU keyed by payload.id for mobile→desktop command requests, guarding against double-stdin in terminal.stdin and duplicate PtyManager side effects. Phase 5 falls out of existing wiring (no new code): DC failure fallback = Phase 2 trySendViaDataChannel catches IllegalStateException and falls through to signaling automatically; auto-reconnect = P2PClient.scheduleReconnect exponential backoff 1s→60s / maxAttempts 10 (already there); recovery auto-switch back = isDcReady re-evaluates on every invoke entry; UI live mapping = Phase 3 dataChannelReady chip. Tests: Android TerminalRpcClientTest +3 dedup / SignalingRpcClientTest +4 transport selection / WebRTCClientTest +1 Trap 1 regression + 12-test regression fix where mockk(relaxed=true) on StateFlow<List<X>> generic-erased .value to a relaxed Object instead of a real List → production-side pairedDesktopsStore.devices.value.firstOrNull threw Object cannot be cast to Iterable → connect() caught and wrapped as "连接失败: ..."; the fix adds every { mockPairedDesktopsStore.devices } returns MutableStateFlow(emptyList()) in test setup. Desktop mobile-bridge.test.js gains 14 new tests covering LRU dedup (5 angles: TTL / capacity eviction / non-whitelisted frame types / JSON-RPC responses untouched / missing payload.id pass through) + sendToMobile DC-first vs signaling-relay double-send fallback (5 angles: DC OPEN single DC / readyState shape normalisation / DC missing double-send / DC closed double-send / missing relay client does not throw) + guard rails 2. All three Android suites green (11 + 15 + 21) + 14 new desktop tests + the rest untouched. Real-device E2E §5.3 5-scenario matrix is on the user: LAN same WiFi DC second-level handshake / cellular TURN relay path / double-NAT 3G symmetric should fallback signaling / DC working forcibly killed → fallback ≤ 3s / DC recovered auto-switches back. Design doc docs/design/Android_Remote_Terminal_Plan_A1.md v1.0 includes §1.2 full analysis of three traps (setOnForwardedMessageReceived single listener / DC inbound vs signaling forward two independent paths / P2PClient.sendCommand is DC-only but uses its own envelope incompatible with TerminalRpc) + §3.7 rationale for not reusing :core-p2p DataChannelTransport (terminal envelope JSON vs sync binary P2PMessage are not interchangeable) + §5.3 real-device E2E 5-scenario acceptance matrix. Telemetry [SignalingRpc.metric] path=dc|signaling reqId is live; first-week fast-path-fraction target ≥80% on user base ≥10 devices; below 80% indicates DC unreachable more than expected and needs diagnosis. Distribution: desktop binary v5.0.3.52 → v5.0.3.53 rebuilt; CLI chainlesschain npm 0.161.12 unchanged (Plan A.1 work all under android-app/ + desktop-app-vue/ + docs/); Android versionCode 503052 → 503053 / versionName 5.0.3.52 → 5.0.3.53 per feedback_android_tag_follows_desktop align-with-desktop convention.
Plan A Remote Terminal: Android↔Desktop PTY end-to-end (Phase 1-4 all landed + 162 tests green)
User pain point: "I have many terminals open on my PC, can my Android phone see their output and remotely send commands?" Hard constraint: external terminals already running on Windows cannot be attached by another process (OS handles are private to the parent). Solution Plan A: ChainlessChain desktop uses node-pty to host new terminal sessions; reuses the existing #21 Remote Operate signaling-relay channel to stream stdin/stdout to Android. Phase 1 Desktop main process: PtyManager (lazy node-pty + 256KB ring buffer + 24h idle kill + shell whitelist pwsh/cmd/bash/wsl + 8 concurrent limit) + RingBuffer (byte-aware FIFO, intentionally not persisted to disk — safety > durability since terminal stdout often contains API keys or git diffs of .env files) + terminal-handlers.js (8 WS topics) + terminal-ipc.js (V6 native IPC bridge) + confirmation-dialog.js (dangerous-keyword Electron messageBox + permanent trust per-cmd cache). startWebShell accepts ptyManager + terminalRequireConfirmation; handleMobileCommand adds terminal.* namespace + mobile-bridge per-peer stdout/exit subscription fanout. Phase 1.5 cc ui mirror: packages/cli/src/gateways/ws/topic-handler-attachment.js extracts the ws-cli-loader dispatcher wrap as a reusable ESM helper; cc ui agent-runtime.startUiServer calls it — cc ui users also get /terminal. Phase 2 Cross-shell UI: web-panel useTerminal composable (singleton fanout via module-level sub map + base64↔UTF-8 encoding) + Terminal.vue route /terminal (xterm.js lazy import + multi-session tabs + history backfill + ResizeObserver + dangerous-keyword toast) + sidebar entry + i18n; V6 plugin widget plugins-builtin/terminal/plugin.json + shell/widgets/TerminalWidget.vue + shell/TerminalPanel.vue (xterm.js + IPC bridge electronAPI.terminal.*) + slash command /terminal. Phase 3 Android: TerminalRpcClient.kt (reuses SignalingRpcClient envelope pattern + observeStdout/observeExit SharedFlow) + TerminalWebView.kt (WebView↔Kotlin JS bridge) + xterm-shell.html + xterm.js / addon-fit / xterm.css vendored to assets/terminal/ + TerminalListScreen / TerminalSessionScreen Compose + softkey toolbar (Ctrl/Tab/Esc/arrows/Ctrl+C/D) + NavGraph 2 routes + RemoteOperateScreen "Open Remote Terminal" entry. Phase 4 Resilience: requireConfirmation wired to desktop systray + paired_devices/permission-gate (reuses existing p2p-command-adapter) + mobile-bridge stdout fanout (per-peer subscription map) + reconnect history backfill + 24h idle kill. Tests 162 new all green — Desktop main 61 (RingBuffer 7 + PtyManager 15 + terminal-handlers 15 + terminal-ipc 12 + confirmation-dialog 5 + ws-smoke integration 6 + real PTY spawn cmd.exe integration 1 — completes in 5.08s, end-to-end stdin echo PLAN_A_PROBE_42 stdout stream contains probe) + CLI cc ui 21 (PtyManager 10 + handlers 8 + ws-mirror-smoke 3 with real ChainlessChainWSServer + attachTopicHandlers + real WS client) + Web Panel 17 useTerminal composable + 3 e2e (real cc ui subprocess + real WebSocket + real shell stdin/stdout round-trip via probe echo) + Android 10 TerminalRpcClientTest (full happy path + flow event fanout). Also fixed pre-existing test drift — widget-registry.test.ts (PREVIEW_WIDGETS already extended to 7 entries; bridge-mtc + federation-governance were missing) / dashboard-store.test.js (no mock for mcp.list_tools sendRaw reply, drift since commit d9cc41432) / views-mount-smoke.test.js 5 tail views (Projects/VideoEditing/P2P/Memory/Git hit Notification + Pinia cross-test state pollution under 50+ files parallel suite) / Projects-folder-picker.test.js deleted (tested UI no longer exists). Design doc docs/design/Android_Remote_Terminal_Plan_A.md + user doc docs-site/docs/guide/remote-terminal.md synced to both doc sites. Future A.1 stream traffic through WebRTC DataChannel to bypass relay bandwidth bottleneck / Future B read-only snapshot of already-running external terminals via screenshot + OCR + Win32 SendInput left for later.
Remote Operate Plan A + B infrastructure landed: WebRTC signaling pass-through + STUN/TURN deployment + iceServers credential signing
Plan C (v5.0.3.50) signaling-forward wired low-frequency commands at 100-400ms p99 but two hard constraints remain: throughput (relay bandwidth shared across all clients — streaming tokens / files / video cannot pass) + privacy (the relay server can read plaintext payloads beyond public wss TLS). Plan A+B closes both: real WebRTC P2P DataChannel = end-to-end encryption + direct-link bandwidth. Complete three-tier picture: low-frequency commands → Plan C signaling forward / high-throughput streaming + files → Plan A WebRTC DC / NAT-traversal fallback → Plan B STUN/TURN. Clients fall through by scenario: prefer DataChannel, fall back to signaling forward on failure. Plan A core changes: (1) relay server.js handleMessage switch adds case offer/answer/ice-candidate/ice-candidates/peer-status on the same forwarding path as type=message + injects from field (taking the ws-registered peerId, parity with LAN signaling-handlers — desktop handleOffer reads socket.peerId or message.from to identify the peer; the relay path must explicitly inject from). (2) Desktop main startRelayClient.onMessage collapses to a unified dispatch instead of per-type case: pair-ack still routes alone to write sessionState; the rest (command:request / offer / answer / ice) goes to mobileBridge.handleSignalingMessage, which already dispatches by msg.type to handleOffer / handleAnswer / handleICECandidate / handleP2PMessage — LAN and relay paths become fully equivalent. Plan B core changes: (1) coturn 4.6 docker compose host-network UDP relay port range 49152-65535 host-network avoids NAT translation, listening 0.0.0.0:3478 UDP+TCP + 5349 TLS, domain turn.chainlesschain.com A record 47.111.5.128, Let_s Encrypt cert via acme.sh @gitee mirror (GitHub access throttled in mainland China), use-auth-secret time-limited credentials. (2) signIceCredentials(userId) signing: username = expiry-ts:user-id, credential = base64(HMAC-SHA1(TURN_SECRET, username)); iceServers returns three-tier priority list stun:turn.chainlesschain.com:3478 + turn:3478?transport=udp/tcp + turns:5349 with credentials. TTL 24h is enough for a single-device session — by the time it expires the user has likely re-paired anyway. CC_TURN_SECRET env is mandatory with no source-level fallback and never hardcoded (no fork can mint working credentials); without it the system degrades to STUN-only (LAN + dual-NAT-friendly scenarios still WebRTC; cross-NAT unavailable). (3) iceServers no longer embedded in QR — QR payload 650+ chars + high error correction at 280px crashed scan recognition (verified 2026-05-14: 30s blocking with no detection); switched to async push after scan: when desktop pair-ack matches it calls pushIceServersToMobile(ackPayload) over both LAN signaling + the public relay (dual-send) with type chainlesschain:ice:config payload {pcPeerId, iceServers, iceExpiry} for mobileDid. Android WebRTCClient.setOnForwardedMessageReceived intercepts that type, persistIceConfigMessage upserts PairedDesktopsStore.iceServersJson; SignalingRpcClient.handleIceConfigMessage adds a race-tolerant backup. (4) Android WebRTCClient.createPeerConnection calls resolveIceServersFor(pcPeerId) using stored iceServers (TURN included), with expiry/missing fallback to Google STUN; parseIceServersJson accepts urls as either string or array. Full Plan A+B data flow: pairing — phone scans QR → pair-ack → desktop persists SQLite + pushes iceServers → phone receives ice:config → PairedDesktopsStore upsert; WebRTC connection — phone opens RemoteControl → WebRTCClient.connect(pcPeerId) → createPeerConnection with stored iceServers (TURN included) → createOffer → signaling forward (LAN or relay) → desktop handleOffer → setRemoteDescription → createAnswer → forward back → ICE candidate exchange via forward, STUN/TURN punches → DataChannel open. Command path split: low-freq SignalingRpcClient relay forward = Plan C / high-throughput DataChannel direct = Plan A / NAT-hard TURN relay = Plan B (DataChannel through relay). Aliyun security groups must allow UDP 3478 / TCP 3478 / TCP 5349 / UDP 49152-65535 to 0.0.0.0/0 — without it the coturn container runs but is externally unreachable, ICE gathering fails. Known constraints / outstanding: iceServers TTL 24h — once expired, fallback Google STUN cannot traverse NAT (mobile-side detection of approaching expiry to request fresh credentials over signaling lands later); WebRTC P2P real-device cross-NAT verification still pending — full file-transfer test on phone 4G + desktop home WiFi planned before v1.4 GA; Signal Protocol E2EE waits for Plan A DC to land first (DC is already direct + TLS, marginal gain from Signal); coturn credential management API needs backend HMAC signing API in the long run, gated by user identity. Design doc docs/design/Android_Remote_Operate_Plan_AB.md.
v1.2 GA feedback 5+3 integrated: desktop↔mobile project workflow P1+P2+P3A + delete fix + daily templates
v1.2 GA feedback integrated 5+3 items: issue 21 https://github.com/chainlesschain/chainlesschain/issues/21 #2/#3/#4/#5/#7/#8. North star: phone-side AI project interaction should be as smooth as desktop. Two phases. Phase 1 (earlier P0 before GA): A.3 ADR review + B.6 PQC strict-mode verifier + B.2 trim web-shell multisig cc subprocess cold-start + AI-3 forward-compat seam + 2 bug fixes already landed commits 348896382 / e24386d00 / b1c7cfd95 / 45a88270e / c0d061328 / 409afddcd. Phase 2 (mid-stage after GA feedback) project workflow 4 pieces: #2 project undeletable fix (commit fc24f9856) EnhancedProjectCard had no delete UI at all the old ProjectListScreen delete code was dead never wired into NavGraph added 3-dot menu + AlertDialog confirm onDeleteClick invokes viewModel.deleteProject DAO softDelete status deleted Room Flow auto removes from list. #3 templates to daily life 11 entries (commit 99d38bf69) under the L1+L2+L3 mobile positioning users are not developers the original 11 IDE templates Android React Spring Flutter mismatch real usage scenarios rewrote ProjectTemplates as daily-life templates shopping list travel plan reading notes idea capture fitness plan recipe study plan household ledger work journal meeting minutes blank TemplateCategory added 5 new categories DAILY TRAVEL STUDY HEALTH FINANCE. #4/#7 desktop CLI + REMOTE handler P1 (commit 32ccabdb5) packages/cli/src/lib/project-runtime.js SQLite cascade native better-sqlite3-multiple-ciphers better-sqlite3 sql.js WASM auto fallback + Electron userData path resolution Win macOS Linux + cc project init/list/show/delete 4 subcommands write directly to desktop chainlesschain.db WAL concurrency safe. desktop-app-vue/src/main/remote/handlers/project-management-handler.js 6 actions list get init delete listFiles getFile exposed to Android L3 REMOTE calls reusing desktop DatabaseManager. CLI 7 integration tests + handler 21 unit tests all pass. #4 Android to Desktop reverse sync P2 (commit 2646bbb4e) audit found desktop to mobile sync was working mobile-bridge-sync _fetchProjects walker + Android ProjectSyncApplierImpl but reverse mobile to desktop was broken SocialSyncWalker did not include projects table. Added ProjectDao.getProjectsSinceCursor no status filter so status=deleted also emits + ProjectSyncWalker.kt feature-project about 120 lines op mapping CREATE/UPDATE/DELETE snake_case JSON aligned with desktop + CompositeSyncRepositoryWalker.kt :app/sync aggregates SocialSyncWalker + ProjectSyncWalker + SyncWalkerModule.kt Hilt @Binds replaces feature-p2p single-walker binding. P2PModule.kt commented out the old binding. ProjectSyncWalker 12 tests + CompositeSyncRepositoryWalker 7/7 tests all pass. Also fixed 5 pre-existing feature-project tests kotlin.test.* org.junit.Assert.* imports to unblock :feature-project:compileDebugUnitTestKotlin. #5/#8 web-shell Projects + in-process WS P3 Part A (commit bfdde637d) desktop-app-vue/src/main/web-shell/handlers/project-handlers.js 6 in-process WS topics wrap the P1 ProjectManagementHandler DRY reuses the same handler to serve web-shell + mobile L3 REMOTE avoiding ws.execute(cc project …) asar:true subprocess cold-start 6-10s. packages/web-panel/src/views/Projects.vue rewritten as a real project management page 4 stats + state/name filter + table with id/name/type/status/sync_status/updated_at + Detail drawer with Descriptions + file list + Create modal with 10 types useShellMode.isEmbedded dispatches between in-process and ws.executeJson fallback. The original Projects.vue project init/setup/templates content was moved to ProjectInit.vue at route /project-init to keep backward access. project-handlers 7 unit tests all pass. No version bump; will release alongside the P1 main scope once P3 Part B Android ProjectCommands.kt lands and the user has verified P1+P2+P3A.
Android v1.3+ P0 prerequisites GA-independent closed + AI-3 forward-compat + 2 bug fixes
P0 prerequisite batch before v1.2 GA. Issue 21 https://github.com/chainlesschain/chainlesschain/issues/21 A.3 ADR review + AI-1 amend (commit 348896382): 8 ADRs audited — 5 keep + 2 amend (ADR-7 cc-mobile.json was never created and actually goes through user_settings + mobile.* scope; ADR-8 registry is disk-first + push-based, not pull) + 1 revise (ADR-2 M2 DID wallet still uses software Ed25519, which blocks B.3 DID rotate). ADR-2 option A/B/C decision waits on v1.2 GA Play Console API-level data. Same commit adds design doc §10 v1.3+ scope triage layering across 12 sub-items (P0/P1/P2) plus 5 dependency chains. B.6 PQC strict-mode verifier (commit e24386d00): packages/core-mtc/lib/landmark-cache.js gains strictPqMode opt-in flag + _assertStrictPqMode landmark-level gate + _assertStrictPqModeForSnapshot per-snap gate + STRICT_PQ_MODE_VIOLATION error code + CLASSICAL_ALGS constant. Reading A semantic rejects any partial sig + publisher_signature where alg === Ed25519. Backward-compatible with the existing heterogeneous federation data format (zero schema changes, zero producer-side changes). B.2 skip cc subprocess cold-start (commit b1c7cfd95): desktop-app-vue/src/main/web-shell/handlers/multisig-handlers.js adds 7 in-process WS topics that mirror the CLI --json output shape (multisig.list / show / policy.show / cancel / finalize / sweep + marketplace.consume). The topics invoke openMultisigManager() from the CLI multisig-runtime.js via dynamic-import across the CJS/ESM boundary. Multisig.vue gains callMultisigTopic() helper that dispatches via useShellMode().isEmbedded; all 7 ws.executeJson sites switch. Perf: asar:true subprocess cold-start 6-10s → in-process ~20ms (SQLite open) + query, 60-100x speedup. Zero UX changes. AI-3 SkillMetadata.signature forward-compat (commit 45a88270e): Android Kotlin adds ManifestSignatureVerifier interface + sealed VerificationResult.{Accepted/Rejected(reason)} + object NoOpManifestVerifier always-accept stub. SkillMetadata gains signature: String? = null field + init invariant. RemoteSkillRegistry gains @Volatile manifestVerifier + setManifestVerifier(v) swap seam + updateFromRemote runs the verifier per-skill (Accepted merges; Rejected Timber.w warn-logs + skips). When marketplace M0 (#21 AI-5) lands, app injection of a real Ed25519/SLH-DSA hybrid verifier is enough; callers do not change. Bug fix 1 wear test imports (commit c0d061328): CcPhoneDecisionListenerTest since cc08da0b0 (v1.2 #20 P0.2) used kotlinx.coroutines.GlobalScope.launch with delay() but the imports were missing launch / delay / GlobalScope / DelicateCoroutinesApi, which blocked the entire :app:compileDebugUnitTestKotlin. Added 4 imports to unblock. Bug fix 2 B.6 disk-load gate (test-driven discovery in this QA sweep): LandmarkCache.loadFromDisk() called _validateAndStoreSnapshot directly, bypassing ingest's strict-mode gate; an Ed25519 landmark cached when strictPqMode was off would later be accepted by a strictPqMode=true cache on disk reload (silent strict invariant violation). Fix: moved the per-snapshot strict check into _validateAndStoreSnapshot so both ingest and disk-load paths run through the gate; +2 disk-load integration tests lock the regression. Tests: B.6 landmark-cache-strict-pq-mode 11/11 (9 original + 2 disk-load integration) + B.2 multisig-handlers 23/23 unit tests via runtimeFactory injection seam + AI-3 ManifestSignatureVerifier 10/10 + SkillMetadataTest 9/9 + RemoteSkillRegistryTest 38/38 regression + web-shell 379 regression across 25 test files, all pass. No version bump: this batch is the v1.2 GA prerequisite; will release with P1 main scope after v1.2 GA feedback lands.
Android Remote Operate Plan C signaling-forward RPC: mobile remote really wired to the desktop
After pairing landed in v5.0.3.49 (W3.7 Flow B QR), the next step is letting the mobile actually operate the desktop. Three candidate paths: A WebRTC P2P direct (big engineering) + B STUN/TURN traversal (medium) + C reuse the signaling-forward pipe that pair-ack already proved (small). Plan C ships first pragmatically: pair-ack already routes through forward in both directions, the desktop handleMobileCommand is already in place, only the mobile-side SignalingRpcClient and a minimal UI are missing. A+B left for follow-up (video streams, real-time sync, high-frequency small messages). (1) SignalingRpcClient lands (app/.../remote/client/SignalingRpcClient.kt): builds {type:"chainlesschain:command:request", payload:{id, method, params, auth, timestamp}} → PairingSignalingGate.sendAck; one-shot installs setOnForwardedMessageReceived listener and matches requestId to CompletableDeferred to resolve responses; 30s withTimeout safety net; automatically resets the gate, switches to the public relay URL, re-registers and retries once when the LAN sendAck fails — same pattern as ScanDesktopPairingViewModel pairing fallback. (2) RemoteOperateScreen + ViewModel (app/.../remote/ui/RemoteOperateScreen.kt): minimal UI with three chip buttons (Ping / System Status / System Info) + response JSON display + unpair; the home screen connected-desktop card taps into NavGraph route remote_operate/{peerId}. (3) PairedDesktopsStore (core-p2p/.../pairing/PairedDesktopsStore.kt): SharedPreferences JSON of paired desktops (pcPeerId / deviceName / lanSignalingUrl / relayUrl / pairedAt / lastSeenAt); upsert idempotent by pcPeerId; the home screen now reads from this store instead of p2pClient.connectedPeers because Plan C does not maintain a persistent P2P connection — once the post-scan signaling drops, connectedPeers is empty and the UX would look like not-connected right after a successful pairing. (4) Desktop RelayClient (desktop-app-vue/src/main/p2p/relay-client.js): outbound long-lived connection to wss://signaling.chainlesschain.com, registers the desktop pcPeerId (must match mobileBridge.peerId, otherwise off-LAN phones cannot find the target peer), onMessage routes pair-ack / regular mobile commands into recordPairAck / handleMobileCommand (same pipeline as LAN); exponential backoff reconnect capped at 60s. (5) mobile-bridge.handlePairAckFromRelay bug fix: main/index.js was calling this.mobileBridge?.handlePairAckFromRelay(...) but the method did not exist; the optional-chain swallowed it silently, so the relay path pair-ack triggered no event. Added an EventEmitter notification symmetric with the LAN branch. (6) MobileBridgeHeaderStatus.vue web-panel header shows paired-mobile count, polling cc p2p devices --type mobile every 5s; parseJsonOutput now skips CLI log-prefix lines [AppConfig] / [DatabaseManager] etc. to stop false-positive matching them as JSON-array starts. (7) i18n: 11 RemoteOperateScreen strings extracted into values/strings.xml + values-zh-rCN/strings.xml — ro_title / ro_subtitle / ro_peer_id_fmt / ro_quick_commands / ro_cmd_ping/status/info / ro_executing_fmt / ro_error_label / ro_response_label / ro_unpair. Tests: 3 new unit test files / 20 tests all green — PairedDesktopsStoreTest 7 (mocked SharedPreferences instead of Robolectric, orders-of-magnitude faster startup) / SignalingRpcClientTest 7 (FakeSignalClient + CapturingGate; happy / no-DID fail fast / LAN→relay fallback / double-fail / response with error field / real withTimeout / unknown rid silent ignore) / RemoteOperateViewModelTest 6 (mockk + StandardTestDispatcher state transitions + null-message error fallback + unpair calls store.remove). Two key technical decisions: use runCurrent() instead of advanceUntilIdle() — SignalingRpcClient.invoke uses withTimeout(30000) on virtual time and advanceUntilIdle would push the virtual clock past 30s and falsely trigger the timeout; added testImplementation org.json:json:20240303 — the Android SDK stubbed org.json.JSONObject silently returns defaults under isReturnDefaultValues=true instead of really parsing JSON. ScanDesktopPairingViewModelTest signaling gate failure surfaces Failed now expects sendAckCallCount == 2 (LAN + relay both called). Desktop vitest 7600+ suite all green. Plan C real-device E2E is on the user-side checklist, same pattern as Flow B verification. Constraints: one signaling hop + one public-relay hop puts p99 latency at 100-500ms — acceptable for low-frequency commands; relay traffic is TLS but the relay server can see the payload, so end-to-end encryption requires Signal Protocol session; relay outage = Plan C unavailable, LAN still works. Roadmap: Plan C landed → Plan A.1 DataChannel reuse → Plan A.2 high-throughput true P2P direct to bypass relay bandwidth → Plan B STUN/TURN traversal. Design doc docs/design/Android_Remote_Operate_Plan_C.md. Distribution: desktop binary v5.0.3.49 → v5.0.3.50 rebuilt; chainlesschain npm version unchanged (no CLI changes); Android versionCode/Name unchanged (v1.0.0 GA holds — this Plan C round is desktop-first; the full Android v1.1 minor will ship the complete mobile client). All three doc sites synchronized this round: docs-site / docs-site-design pull the new Plan C design doc through the sync scripts; docs-site tagline bumped to v5.0.3.50; README / README_EN gain this changelog entry.
M-of-N multisig Phase 1d + Phase 2a marketplace mediator + Phase 2b web-panel Multisig view + Android v1.1 W3.7 Flow B QR pairing closes + test backfill
Four main lines this release. (1) `@chainlesschain/core-multisig` package + `cc multisig` CLI lands (commit 3c890dcac, v1.2 m-of-n Phase 1d): Phase 1 ships 5 lib files — policy.js (domain {m,n,members[],requirePqc,defaultExpiryMs} validate / normalize); store.js (SQLite 3-table schema — proposals / signatures / policies — plus 5 helpers); proposals.js (state machine pending → reached → consumed plus cancelled / expired terminal); signing.js (JCS canonicalize + DOMAIN_PREFIX "MULTISIG:" replay protection + Ed25519 / SLH-DSA dispatcher + verifyThreshold strip-all-sigs); governance-log.js (append-only JSON Lines audit log capturing every state transition). 75 lib unit tests (policy 14 + signing 21 + proposals 20 + store 12 + governance-log 8) all pass. cc multisig CLI 8 subcommands: propose / sign / cancel / finalize / list / show / sweep / policy {set,show}; all support --json; 10 CLI integration tests pass. SQLite driver cascade: native better-sqlite3-multiple-ciphers / better-sqlite3 falls back to sql.js WASM on load failure — CLI works out of the box on any platform without per-platform native prebuild. Unlocks three canonical domains: marketplace.purchase / did.rotate / cross-chain bridge. Three test-infra fixes: core-multisig vitest.config.js sets globals: true (vitest 4 rejects CJS require("vitest")); 5 test files switch to ESM import; multisig-cli.test.js import path drops .js suffix on @chainlesschain/core-mtc/signers/ed25519 (core-mtc exports key has no suffix). (2) Phase 2a marketplace.purchase mediator (commit 2755093d0, design doc §6.1 lands): `cc marketplace purchase <itemId> --amount-fen N --buyer <did> --key <hex> [--threshold-fen N] [--item-name <name>]` — when amount < threshold (default `LARGE_PURCHASE_THRESHOLD_FEN = 100000` fen = ¥1000) the command takes the direct path (CLI stub prints "purchased", no real payment processor); when amount ≥ threshold a `marketplace.purchase` domain policy is required, otherwise exit 2 `no_policy`; with a policy in place, `mgr.propose` returns the proposalId so the other signers can add their signatures. `cc marketplace consume <proposalId>` — requires `domain == "marketplace.purchase"` and `state == "reached"` before executing; after finalize it prints the order payload and writes a `consumed` event to the governance log; wrong domain or state both exit 2. Shared runtime in `packages/cli/src/lib/multisig-runtime.js` (new file) extracts the SQLite cascade (better-sqlite3-multiple-ciphers → better-sqlite3 → sql.js), manager loader, and readSecretKey / readJsonArg helpers that used to live inline inside commands/multisig.js, so commands/marketplace.js can reuse the same code path; commands/multisig.js was refactored to use the shared module, dropping ~130 duplicate lines while leaving Phase 1 behaviour untouched (10/10 integration tests still pass). 8 new E2E tests pass (`packages/cli/__tests__/integration/marketplace-multisig-e2e.test.js`): (a) full ¥1500 2-of-2 walkthrough — policy set → purchase opens proposal → two signers sign → reached → consume → finalize → governance.log records four events `proposed`/`signed`×2/`reached`/`consumed`; (b) ¥500 takes the direct path without creating a proposal; (c) `--threshold-fen` overrides the default; (d) large purchase without a policy → exit 2 blocked; (e) consume on a pending proposal → exit 2 `proposal_state_pending`; (f) consume on a wrong-domain proposal → exit 2 `wrong_domain`; (g) `--help` text verified; (h) Phase 1 compatibility regression. 18 multisig integration tests pass overall (Phase 1 10 + Phase 2 8). marketplace.purchase becomes the first mediator wired to a real business path. (3) Phase 2b web-panel Multisig view lands (commit c758492d9, design doc §8.1 lands): web-shell (default desktop entry) gains an M-of-N multisig view + operations panel that reuses Phase 1 CLI via `ws.executeJson("multisig list --json")` calls. New `packages/web-panel/src/views/Multisig.vue` (468 lines): six top stat cards — total / pending / reached / consumed / cancelled / expired, each with an Ant icon + colour token. Two tabs: Proposal list — table columns (ID / Domain / State / Sigs / Created / Expires / Actions) + state filter (pending / reached / consumed / cancelled / expired) + domain filter; row actions (detail / cancel / execute purchase — marketplace.purchase reached only). Domain policy — lists known domains (marketplace.purchase / did.rotate / crosschain.outbound) with policy detail and member expansion. Detail drawer (640px) Descriptions render domain / state / threshold / sigs / initiator / timestamps / payload (pretty JSON) + signature list (signer DID + alg + timestamp) + operation buttons (cancel for pending|reached / execute purchase for marketplace.purchase reached / finalize for other reached) + info Alert "web shell does not hold private keys; sign goes through CLI". Top action bar: refresh + sweep expired (`cc multisig sweep`). AppLayout.vue adds the multisig menu item to the security/audit group (TeamOutlined icon) + collapsed-mode parity + i18n fallback "M-of-N 多签" (`appLayout.items.multisig` displays Chinese when unconfigured). router/index.js adds `{ path: "multisig", name: "Multisig", component }`. WS communication goes through the CLI subprocess (`ws.executeJson("multisig list --json")` on the CLI WS server `_executeCommand` path); first cold-start is 6–10s (asar:true overhead, per `mtc-status-handlers.js` comment) — acceptable for Phase 2. Same SPA auto-available in both desktop web-shell and `cc ui` (per memory `feedback_cross_shell_feature_pattern`). Phase 3 follow-up: private-key signing UI (needs UnifiedKeyStore wired) / in-process WS handlers (`multisig.list` / `multisig.show` / ...) to shave latency / real-time push (currently `onMounted` one-shot, no WS subscription) / Marketplace.vue integration entry (purchase modal flowing into the multisig pipeline). (4) Android v1.1 W3.7 Flow B QR pairing lands (commit c47cbc649): desktop displays the QR / phone scans — the standard UX pattern in mainstream apps (WeChat / Alipay / Discord / WhatsApp Web). Camera-scans-screen is dramatically more reliable than the reverse direction. Verified end-to-end on real Xiaomi 24115RA8EC hardware. Cross-module DI split: PairingSignalingGate.sendAck interface lives in :core-p2p so :feature-p2p does not reverse-depend on :app; WebSocketPairingSignalingGate.sendAck implementation in :app serializes via ensureRegistered + Mutex; WebRTCClient.SignalClient.sendForwardedMessage(toPeerId, payload) bridges the mobile signaling forward. Mobile UI: ScanDesktopPairingScreen + ScanDesktopPairingViewModel use the non-social QRCodeScannerScreen (ZXing pass-through; the social variant validates and would reject our desktop-pairing JSON); NavGraph + SettingsScreen gain a "Scan desktop QR" entry. Desktop WS topics trio in desktop-pair-handlers.js: desktop.pair.generate-qr (6-digit code + payload + pcPeerId three-tier fallback: mobileBridge.peerId → deviceManager.getCurrentDevice → "desktop-unknown") / desktop.pair.poll-ack (idle / waiting / acked / expired four states) / desktop.pair.reset; mobile-bridge.js adds this.peerId persistence + intercepts type=pair-ack via recordPairAck, then writes SQLite paired_devices. Vue UI: MobileBridge.vue gets a Flow B tab (default) + Flow A + manual entry 3-tab layout; antd.js registers AQrcode. End-to-end chain on real hardware: Xiaomi 24115RA8EC desktop QR → ML Kit scan → signaling pair-ack → desktop mobileBridge intercept → recordPairAck match → CLI pair-from-qr writes SQLite → Vue refreshes device list. Nine production traps swept. (5) Test backfill: ScanDesktopPairingViewModelTest.kt (new, 10 tests) covers every validation branch of onQrScanned plus happy path + retry + idempotent + malformed JSON, built on MockK + StandardTestDispatcher + FakeGate that captures sendAckCallCount. desktop-pair-handlers.test.js (new, 19 tests) covers all three handler factories plus recordPairAck: generate-qr (6 cases) / poll-ack (4 cases using vi.useFakeTimers for the expired case) / reset (1 case) / recordPairAck (4 cases). Android :feature-p2p:testDebugUnitTest 41s all green (138 actionable tasks); Desktop 3 files / 45 tests all green. Distribution: desktop binary v5.0.3.48 → v5.0.3.49 rebuilt (now carries Flow B + multisig source; auto-updater compares 5.0.3-alpha.49 > 5.0.3-alpha.48); chainlesschain npm 0.161.8 → 0.161.9 (CLI gains multisig command + dep @chainlesschain/core-multisig); Android versionCode/Name unchanged (v1.0.0 GA holds), Flow B desktop-first this release, full mobile client follows in the next Android v1.1 minor.
Android M3 capture suite (5/5 code) + M4 RemoteSkillRegistry method-level + ApprovalUI 4-category + ProgressViewer + alias compat window + M7 Android v1.0.0 GA flip
Android v1.0 RFC M3 + M4 closing batch (7 commits / 187 new unit tests) + M7 Android GA flip lands together (commit ffe722162, versionCode 37 → 100, versionName 0.37.0 → 1.0.0). No desktop / CLI source changes; CLI npm 0.161.7 → 0.161.8 (force publish on the release.yml sync track). (1) M3 capture suite goes 5/5 to code: VoiceMode end-to-end voice chain (commit 47bebed80, ASR → REMOTE chat → TTS pipeline); CameraOCR snap-to-KB pipeline (commit a69269ced, ai.ocrImage + knowledge.createNote); LocationTagger via Play Services FusedLocationProvider + Foreground Service (commit 3f5ac8647, GPS flows into createNote.metadata); SharePayloadFlusher feeds SyncCoordinator → knowledge.createNote (commit 3d1a6e3a8, 5 SharePayload variants → note fields, drained at the tail of the 30s push loop, failures re-enqueued, 19 new tests); PushNotifier local channel + FCM skeleton (commit c0d990c91, 4 NotificationChannel — Cowork / Marketplace / SystemAlert / ShareInbox — plus a protocol-neutral CcPushNotificationService entry, 36 new tests; real google-services.json wiring stays on the user via the 5-step android-app/docs/M3_FCM_SETUP.md). (2) M4 D1 RemoteSkillRegistry method-level metadata (commit 6e49270fd): MethodMetadata (name / paramCount / riskOverride / requiresApprovalOverride) + listMethods / getMethod / requiresApprovalForMethod / riskForMethod accessors; knowledge.* and ai.* seeded with 10 methods each (8 riskOverride demos); the other 21 namespaces stay empty pending desktop mobile-skill-whitelist push. 16 new tests. (3) M4 closing pair (commit f4f83cc67): ApprovalUI four-category adapter — ApprovalCategory enum {Sign / Cowork / Marketplace / SystemCritical} + fromMethod inference; AndroidApprovalGate 4-arg overload carries category through (old 3-arg auto-forwards); Dialog swaps icon / tint / title / footer per category. ProgressViewer long-running task panel — LongTaskRegistry @Singleton MutableStateFlow (Pending / Running / Completed / Failed / Cancelled, MAX_TASKS=100 sliding window) + TaskProgressCommandRouter consumes task.* reverse-RPC (update / complete / fail / cancel / remove) + Compose ProgressViewerScreen (StatusChip + Linear / indeterminate Circular + dismiss / clear-terminal). 43 new tests across the trio (9 + 15 + 19). (4) §8.3 alias compat window (commit 0bc8e2797): SkillMetadata.aliases field + internal aliasIndex; get / listMethods / requiresApproval / risk* all route through resolveAlias so renaming a namespace next release doesn't break old callers for one window. 7 new tests. (5) §8.1 README versionName fix + v1.0 GA checklist (commits 0bc8e2797 3da484e9c): android-app/README.md M3 (2/5) → (5/5 code); M4 row gains method-level + ApprovalUI + ProgressViewer; new ANDROID_v1_GA_CHECKLIST.md. (6) M7 Android v1.0.0 GA flip (commit ffe722162): android-app/app/build.gradle.kts versionCode 37 → 100, versionName 0.37.0 → 1.0.0; android-app/CHANGELOG.md adds [1.0.0] - 2026-05-12 GA entry summarising 9 commits + 4 known limitations (FCM mainland-China reach / single peer / offline queue / QRPairing scaffold); android-app/README.md title flips to "🎉 v1.0.0 — GA". Next step: tag v1.0.0 at ffe722162 and push to gitee + github. v1.0 GA still has 4 user-side items remaining: M3 device E2E / M4 D2 device E2E / FCM credentials / M6 perf measurements.
Verification release: build-android keystore fix VERIFIED + density splits 14→4 first user-visible drop + outstanding `../` fully swept
Verification-only release. No desktop / CLI / Android source changes — just runs the three release-pipeline fixes landed after v5.0.3.46 through real CI to prove green. (1) build-android keystore fix VERIFIED (commit f9a7ba716): 49f1440ca had switched android-app/app/build.gradle.kts:79 from `file(...)` to `rootProject.file(...)`, moving the `release.storeFile` resolution base from `:app` module up to rootProject (android-app/). The workflow had `release.storeFile=../debug-ci.keystore`, which under the new base resolves to `<repo-root>/debug-ci.keystore` — gradle could not find the keystore and v5.0.3.46 build-android failed at `:app:validateSigningRelease`. f9a7ba716 drops the `../` from workflow keystore.properties content so `rootProject.file("debug-ci.keystore")` resolves directly to `android-app/debug-ci.keystore` (exactly where keytool writes). v5.0.3.47 release.yml run #25632845952 verified build-android green; 4 Android assets (`app-{arm64-v8a,armeabi-v7a,universal}-release.apk` + `app-release.aab`) correctly land in the Release. (2) Density APK splits first user-visible drop (commit 9865c5c08): merged with v5.0.3.46 but never produced release assets because build-android was broken; this release is the first time it ships to users — per-density × ABI splits add little value with Android 5.0+ runtime resource selection, so dropping them cuts release asset count from 14 to 4 (3 APK + 1 AAB); the AAB still uses the `bundle{}` block for Play Store density delivery. (3) Remaining `../` triple sweep (commit 5a06421cd): f9a7ba716 only fixed the active workflow; keystore.properties.template / docs/guides/KEYSTORE_SETUP.md / orphan android-app/.github/workflows/android-release.yml all carried the same `../` pattern and got swept this round. Convention now uniform across the repo: `release.storeFile=keystore/<name>.keystore` (no `../`), physical keystore at `android-app/keystore/<name>.keystore`. The CI example in KEYSTORE_SETUP.md also gained `working-directory: android-app` so the keystore lands in the right place. The orphan workflow received a header comment noting that nested `.github/workflows/` directories are not picked up by GitHub Actions. Desktop binary rebuilt v5.0.3.46 → v5.0.3.47 with equivalent contents; auto-updater compares `5.0.3-alpha.47 > 5.0.3-alpha.46`, so v5.0.3.46 desktop users will see a real "new version" prompt on restart. `chainlesschain` npm stays at 0.161.7 (no CLI changes; release.yml `cli-tests` job correctly skipped). Android versionCode/Name unchanged but the APK product set shrinks from 14 to 4 because of the density splits drop.
Phase 3d desktop ↔ Android two-way sync suite + Android 0.37.0 seven-feature batch + e2e CI silent-regression fix
Three themes shipped together. (1) Phase 3d desktop ↔ Android two-way sync (12 commits): M2 lands the desktop sync engine (5 ResourceType walkers — note / conversation / did / community / channel — with tombstones + IPC wire-up + 52 tests, surfacing and fixing 3 prod bugs along the way); M3 wires the Android side via dagger.Lazy to break 4 Hilt cycles + Room-persisted SyncRemoteCursor + sync.* JSON-RPC handlers + transport wiring; M4 adds the desktop SyncMobile settings page + DeviceManager + manual pairing form; v1.1 makes SocialSyncWalker actually return data via handlePullRpc + DID auth verification + SyncCoordinator auto-trigger when the socket connects; v1.2 swaps placeholder signatures for real @noble/ed25519 + Android gate 4 verify, so all 4 gates are now strict-verify. (2) Android 0.37.0 (commit 1348636ad, 7 user-visible features): Volcengine SeedASR voice (16kHz mono PCM + 800ms poll + AsrSettingsScreen + Recording/Transcribing dialogs); APK auto-update issue #21 (GitHub Releases android-v tag arm64-v8a + DownloadManager + REQUEST_INSTALL_PACKAGES + Settings "Check for updates" entry); splash purple gradient + rotating ring + TT logo + splash-race fix; Claude coral theme #D97757 primary + dynamicColor=false to preserve brand colour; i18n issue #16 three regions zh-rCN/rTW/rHK explicit qualifiers + AppCompatDelegate locales; biometric toggle wired to AuthVM; KeyManagementScreen DID + public key hex + trusted devices + reset; drive-by fixes for OpenAIAdapter main-thread 12s freeze + 256 rs_* string stubs. (3) e2e CI silent-regression fix (commit e807d576c): drop e2e-tests workflow JOB-level continue-on-error: true — it had been masking 3/3 OS failures as success, leaving "No team IPC interface found" buried for weeks; same batch adds Playwright browsers + npm cache, dropping single-OS time from ~14m to ~6–8m.
cc ui llm.chat parity + intent opt-in toggle + true streaming + Vue Proxy fix
Four interlocking landings. (1) cc ui llm.chat route (f41c4b4e2): the desktop web-shell has had llm.chat since 4eaf90137, but cc ui never registered it → QuickAsk hung 60s on "Stream idle timeout". New packages/cli/src/gateways/ws/llm-chat-protocol.js mirrors the desktop frame protocol (`<topic>.chunk` + `<topic>.result`); new llm-creds.js shares the resolver (explicit options → session creds → VOLCENGINE_API_KEY-style env vars), returning ok:false instantly on missing creds. chat-intent-protocol picks up the same helper, fixing a latent bug along the way: previously `session.baseUrl || "http://localhost:11434"` hardcoded ollama whenever a session lacked baseUrl, killing every cloud provider on machines without local ollama. (2) Intent opt-in toggle (f41c4b4e2): Chat / Agent project/file mode header gets an `<a-switch>`, off by default. Pre-v5.0.3.45 every project/file message went through chat.intent.understand-stream first → 0.5–90s of latency that surprised users coming from the direct-send path. Now defaults to direct send; users who want the confirmation card flip the switch (persisted to localStorage cc.web-panel.chat.intentEnabled). submitUserInput first-line short-circuit. The desktop shell shares this SPA bundle so its behaviour now matches cc ui. (3) chatStream truly streams (35f6e60ea): packages/cli/src/lib/chat-core.js chatStream was a fake async generator that buffered every onToken into an array and only yielded after streamX(...) settled — consumers saw zero progress for the full LLM round-trip. Replaced with a token queue + Promise waiter: onToken push wakes the generator, which yields immediately. Chat / Agent / QuickAsk / chat-intent all benefit. (4) Intent placeholder Vue Proxy reactivity fix (a76e451e2): submitUserInput pushed the placeholder into reactive messages[sessionId] (Proxy-wrapped) but kept mutating through the unwrapped local ref → the set trap never fired → card sat pinned at "Understanding… / 0 tokens / Intent: unrecognised" even with 30+ chunks streamed. Fix: re-acquire the Proxy via `card = msgs[msgs.length - 1]` after push. NPM: chainlesschain 0.161.5 → 0.161.6 → 0.161.7 (0.161.6 was published ahead of productVersion to unblock npm-package users on the QuickAsk hang; 0.161.7 carries the chatStream streaming fix + Vue Proxy fix).
LLM OCR + audit-ipc coverage + chat-intent 90s safeguard
One user-visible feature + three quality follow-ups. (1) Screenshot OCR LLM engine (39b16e29f): Tesseract.js Chinese accuracy is poor; new engine parameter auto/llm/tesseract three-way. auto (default) routes to volcengine doubao vision if configured, else falls back to Tesseract; LLM errors auto-degrade with fallbackFrom / fallbackReason tags. llm forces vision LLM (doubao-1.5-vision-pro, userBudget=medium); tesseract forces local. Provider whitelist Set(["volcengine"]); extending to gemini / openai / anthropic is mechanical once their LLMManager exposes chatWithImage*. V5/V6 shared dialog + web-panel dialog both get an `<a-select>` engine picker + blue/grey/orange tag. (2) chat intent understand 90s wall-clock safeguard (6cbd04c50): sendStream's built-in 60s idle timer rearms on every chunk; a slow LLM that dribbles tokens but never emits `final` leaves the placeholder card spinning forever — AbortController + setTimeout(90s) safeguard. (3) compliance-ipc dead handler cleanup (29006decf): typo'd prefix compliance-classify:* had no callers and even backed onto a different service than the real one; drop both + sync IPC_CHANNELS. (4) audit-ipc.js first unit test coverage (b092673be): zero-coverage gap surfaced by the typo bug — 18 channels + DI refactor + 23 cases. Regression: desktop 1477/1477 + CLI 17,455/17,455.
MTC publisher_signature M-of-N fix + security hardening cascade
Two themes shipped together. (1) MTC `landmark.publisher_signature` fix: producer + verifier must symmetrically strip ALL per-member sigs (not just publisher_signature.sig) before feeding JCS — otherwise tampering with any one member sig in an M-of-N federation breaks publisher_signature, completely defeating the M-of-N threshold. Helper extracted to `@chainlesschain/core-mtc/publisher-signing` subpath, three call sites (batch.js single + federated, landmark-cache.js verifier, desktop governance-multisig.js). `LandmarkCache` defaults `verifyPublisherSignature:true` opt-in, all real-verifier callers enabled. Const BAD_PUBLISHER_SIG → BAD_LANDMARK_SIG (matches spec §11). (2) Eight npm audit sweeps in one week — HIGH 44→0 / MOD 4→0 / LOW 45→0: override `serialize-javascript`/`tar`/`semver`/`undici`/`make-fetch-happen`/`tmp`/`ip-address`/`dompurify`, drop unmaintained `speedtest-net` (native fetch replacement) + `werift` + `hdkey`, split hardhat-stack into standalone `contracts/` workspace, channel-manager DDL hardening, wrtc-compat patches CVE-2024-29415. Bonus: updater renderer progress notifier (notifier-only flow).
chat-panel-v5 three-shell parity + B4 social rolling closure
productVersion .40 → .41, formally shipping the four 5.0.3.40-rolling entries (cred-persist + auto-archive, mofn-sign v2 + webpanel UI, merkle envelope finality, cross-machine sync Phase A + Web Shell Phase 3c.7) plus two new items: (A) V6 default-shell AIChatPanel reverse-aligned to V5 ChatPanel's 4 core features (streaming response + history switching + context memory references + tool-call panel, Phase E commit b33527d31); (B) web-shell ChatPanel v5 port v1+v1.1 (commit 72b13388a) bringing all V5 router protocols / autoSendMessage signals / virtual list / 5 intents / 6 IPCs through WS topics. From now on V5 / V6 / web-shell chat experiences are strictly equivalent — Phase 1.6 default web-shell users no longer miss any V5 chat capability. Also fixed: web-panel views-mount-smoke hitting 30s default timeout under 63-file fork contention via file-level `vi.setConfig({ testTimeout: 60_000 })`.
P2P social full-stack audit-grade closure (§2.2.10 → §2.2.24)
Closes 15 sub-phases at once, taking P2P social from "messages can cross machines" to "fully audited end-to-end loop": cross-machine sync (Phase A — 7 underlying bug fixes) → MTC federation dual-track (B v1) → DID signing + auto peer bridging (B4) → Merkle batch envelope finality (B4-merkle) → cross-machine envelope gossipsub broadcast + on-demand pull (B4-cross) → community-member trust filter (B4-cross-trust) → desktop viewer button + modal (B4-ui) → external archival to filesystem/WebDAV (B4-archive) → M-of-N multi-sig governance (B4-mofn) → cross-federation trust anchors (B4-crossfed) → 13 WS topics for default web-shell (B4-webshell) → 4 composables + MtcAudit.vue UI (B4-webpanel) → sign-as-self v2: renderer sends only IDs (B4-mofn-sign v2, plus fix of a ~1-month-latent IPC bag missing 12 managers) → WebDAV creds via secure-config.enc (safeStorage / AES-256-GCM, plus fix of a ~1-month-latent baseUrl/remoteRoot vs url/remotePath field-name bug) → main-process periodic archival cron (5-min minimum, per-community try/catch, runOnce non-reentrant, lastRun* auto-persisted). Private keys and passwords stay inside main process; the full suite is visible in the default web-shell; audit-grade.
MTC view in-process speedup + CI triple-unblock
Headline: after v5.0.3.39 flipped to `asar:true`, `cc` subprocess cold-start jumped from ~2.5s in dev to 6-10s when packaged, and `Mtc.vue`'s parallel onMounted (`loadStatus` + `loadBridgeStatus` + `loadBridgeSla`) reliably blew the 8s/6s ceilings ("状态加载失败 / 加载桥 MTC 状态失败"). Fix: 3 new in-process WS topics (`mtc.audit-status` / `mtc.bridge-status` / `mtc.bridge-sla`) hit `audit-mtc` / `cross-chain-mtc` libs directly — pure file reads, no spawn, zero asar overhead. `Mtc.vue` branches on `useShellMode().isEmbedded`. Bundled with three CI fixes: macOS `realpathSync` flagged `/var → /private/var` as a symlink → POSIX uses `lstat`; rules-validator flagged a test-fixture `TestDbManager.exec(sql)` → exclude `__tests__/`; CLI subprocess Win cold-start exceeded 10/15s execSync timeouts → unified to 60s.
B4 ASAR surgery — Win install dramatically faster
Windows install substantially reduced: dev-box (NVMe SSD + Defender OFF) measured 190.9s vs 1201s legacy baseline = 6.3× speedup; HDD + Defender ON default-environment strict parity not measured. Re-enabled asar:true (v5.0.3.4-13 fell back to asar:false because the electron-builder walker dropped 4 transitive deps). New surgery runs in afterPack: extract → inject the 4 walker-dropped packages → repack while preserving the original unpackDir decisions. Win wrapper handles workspace symlinks.
MTC v0.11 — Cross-federation trust anchors + offline audit
Decentralized certificate system on Merkle trees: cross-federation trust anchors + third-party auditor + multi-hop routing + gas-aware batch closure + SLA monitoring dashboard. M-of-N multi-sig with heterogeneous Ed25519/SLH-DSA federations + dual-transport service discovery (filesystem + libp2p).
Web Panel bilingual M3
Migrated all major web-panel views to vue-i18n (SpeechSettings / Analytics / Cron / Security / Audit / MCP / Backup / Tokens / MTC / WebAuthn / Community / Wallet / Inference / Organization / Federation, etc.) — full Chinese/English coverage, no hardcoded strings. V6 Preview top-bar gets a language switcher.
Web Shell as default + multi-window
Desktop pivots from "native Vue renderer" to "Electron main embeds ws-server + loads web-panel dist" — true cross-target uniformity. Multi-window scaffold (role-based hash routing + per-role geometry persistence); window.open WS topic lets the renderer spawn new windows.
V6 Chat-First Shell hard-flip
Desktop now defaults to V6 Chat-First Shell (three-pane layout + 5 enterprise providers + dispatcher with widget registry + Ctrl+Shift+A admin console). .ccprofile + MDM push as 3 enterprise customization paths. Top-10 V5 routes all have V6 widget probes.
CLI V2 governance surfaces · 220+
From a2apgov to pmodegov — 136 lib-level V2 governance surfaces (dual-cap + auto-flip + autoStaleIdle + autoFailStuck) + 5,984 V2 tests. Coexists with same-module legacy surfaces via shared nest-blocker.
Android v1.0 Repositioning — L1 Wallet / L2 Capture / L3 REMOTE
Desktop = AI workstation · Mobile = key + capture + remote. Stop chasing desktop skill count — pivot to StrongBox hardware signing + Voice/Camera OCR + REMOTE-invoke desktop skills three-layer architecture. 11-day 7-milestone roadmap · 258+ unit tests · 12 E2E. Read RFC →
Two audiences, one foundation.
"I want a truly private
AI assistant."
- · Local encryption · data never goes to cloud
- · Zero-config · works out of the box
- · Bilingual UI
- · Doctors, lawyers, researchers' daily companion
"I want agent-driven
coding from my terminal."
- · CLI Agent · Claude Code style
- · Cowork multi-agent parallel review
- · MCP tool ecosystem + 9 Skill Packs
- · 159 commands · 30,000+ tests · 220+ V2 governance surfaces
Personal, or enterprise?
Personal
Free / Open SourceFor individuals & independent developers. Full CLI, desktop, mobile experience.
- ✓ All 159 CLI commands + 146 skills
- ✓ U-Key / SIMKey hardware encryption
- ✓ Local Ollama + 10 LLM providers
- ✓ Cowork multi-agent collaboration
- ✓ Windows / macOS / Linux / Android
Enterprise
CustomFor finance, healthcare, legal, government — strict compliance and on-prem requirements.
- ✓ Private deployment + UI branding
- ✓ SSO / SCIM / RBAC / audit & compliance
- ✓ Industry-specific skills (healthcare / legal / research)
- ✓ U-Key batch issuance + DLP + SIEM
- ✓ Dedicated technical support
Same source, every target · v5.0.3.122
Command-line
npm / yarn / pnpm / bun · ~2MB
Android
L1 DID wallet · L2 mobile capture · L3 REMOTE · 25 skills · 383+ tests
See the mobile edition →
Need an enterprise edition?
Pick up the phone.
We provide full-cycle custom services from POC to production for healthcare, legal, research, and government clients. Free needs assessment · 90-day POC guarantee.