RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Diff/nimbalyst-nimbalyst-packages-android-claude ↔ nimbalyst-nimbalyst-packages-electron-claude

Comparison

A · CLAUDE.md · nimbalyst/nimbalystB · CLAUDE.md · nimbalyst/nimbalyst
What each file covers, counted
DimensionSharedOnly in AOnly in BOverlap
Sections015190%
Commands0890%
Section tags33333%

What each file covers

Sections

0 shared · 15 only in A · 19 only in B
  • − Android Package (Native Android App)
  • − Overview
  • − Package Structure
  • − Key Architecture Rules
  • − Transcript
  • − Sync and Encryption
  • − Persistence
  • − Firebase / Notifications
  • − Development
  • − Prerequisites
  • − Commands
  • − Play Store screenshots and video
  • − Builds, signing, and CI
  • − Agent Guidance
  • − Important Files
  • + Electron Package
  • + Development Commands
  • + Testing
  • + Architecture
  • + Main and Renderer Processes
  • + IPC Communication
  • + Preload API
  • + Document Service
  • + Common IPC Issues
  • + Data Persistence
  • + Renderer State Architecture
  • + Logging
  • + Window State Persistence
  • + Theme Support
  • + File Operations
  • + AI Providers
  • + macOS Code Signing & Notarization
  • + Git Worktree Integration
  • + Analytics

Commands

0 shared · 8 only in A · 9 only in B
  • − npm run android:build:transcript
  • − npm run android:test:unit
  • − npm run android:assemble:debug
  • − npm run android:assemble:release
  • − npm run android:bundle:release
  • − npm run android:screenshots
  • − npm run android:walkthrough
  • − npm run android:bundle:signed
  • + npm run dev
  • + npm run dev:loop
  • + npm run build:mac:local
  • + npm run build:mac:notarized
  • + npm run dev:user2
  • + npm run dev:url-handler
  • + npx playwright test e2e/monaco/file-watcher-updates.spec.ts
  • + npx playwright test e2e/monaco/
  • + npx playwright test

Section tags

3 shared · 3 only in A · 3 only in B
  • − setup
  • − code-style
  • − architecture
  • + test
  • + git-pr
  • + api
  •   build
  •   do-not
  •   agent-behaviour

Line diff

+97 added−98 removed34 unchanged25.8% identical
nimbalyst/nimbalyst · packages/android/CLAUDE.md
@@ −1 @@
1# Android Package (Native Android App)
2 
3This package contains the native Android app for Nimbalyst. It mirrors the iOS native app architecture where practical: a pure native mobile shell with a single embedded web transcript view that renders the shared React transcript bundle.
4 
5## Overview
6 
7The Android app is:
 
 
 
 
8 
9- **Pure native Android** using Kotlin and Jetpack Compose
10- **Room-backed** for local persistence
11- **WebSocket-synced** with CollabV3 Durable Objects
12- **End-to-end encrypted** using the same seed + user-derived key model as iOS
13- **Transcript-rendered** through a single `WebView` that loads the bundled React transcript UI
14 
15Voice agent features are intentionally out of scope for Android.
 
 
 
16 
17## Package Structure
18 
19```text
20packages/android/
21 app/
22 src/main/java/com/nimbalyst/app/
23 attachments/ # Image attachment preparation/compression
24 auth/ # Auth callback parsing
25 crypto/ # AES-GCM + PBKDF2 key derivation
26 data/ # Room entities, DAOs, repository
27 notifications/ # Android notification + FCM token plumbing
28 pairing/ # QR payload parsing and persistent pairing state
29 sync/ # WebSocket sync manager and wire protocol
30 transcript/ # WebView host and JS bridge
31 ui/ # Compose screens and app shell
32 src/test/ # Unit tests
33 src/transcript/ # Shared React transcript bundle entrypoint/assets
34 scripts/ # Transcript asset sync helpers
35```
36 
37## Key Architecture Rules
38 
39### Transcript
 
 
40 
41- The transcript UI lives in `src/transcript/main.tsx` and is bundled into Android assets.
42- `TranscriptWebView.kt` is the Android host. `TranscriptBridge.kt` is the only place JS bridge actions should be decoded and routed.
43- Keep transcript behavior aligned with iOS unless Android-specific UX requires a different path.
44 
45### Sync and Encryption
46 
47- `SyncManager.kt` owns the device sync lifecycle, room joins, index updates, queued prompt handling, and session control messages.
48- `CryptoManager.kt` must remain wire-compatible with iOS and desktop. Be cautious with any PBKDF2, AES-GCM, or payload format changes.
49- User routing identity and crypto identity are distinct. Do not collapse them back into a single field.
 
 
50 
51### Persistence
 
 
 
 
52 
53- Room is the source of truth for local Android UI state.
54- Prefer repository/DAO changes over screen-local state duplication.
55- If you add persisted fields, update schema, migrations, and any seed/demo paths together.
 
56 
57### Firebase / Notifications
58 
59- `app/google-services.json` is local environment config. Do **not** commit it. The `google-services` Gradle plugin is applied conditionally (only when the file exists), so a build without it stays green and push stays inert.
60- Client push registration lives in `notifications/NotificationManager.kt`.
61- Server push delivery lives in the collab server, which is the sibling `nimbalyst-collab` repository, not this monorepo. Clone it next to this repo at `../nimbalyst-collab` (override with `COLLAB_SERVER_PATH`); collab tests are gated by `RUN_COLLAB_TESTS=1`. See `.github/workflows/ci.yml`. Android push changes usually require coordinated client + server work.
62 
63## Development
 
 
 
64 
65### Prerequisites
66 
67- Android Studio Ladybug / AGP-compatible version for this project
68- JDK 17 for Gradle builds. The project targets `JavaVersion.VERSION_17` and `jvmTarget = "17"`, and Temurin 17 matches CI. A non-17 JDK (e.g. GraalVM) can fail the AGP `jlink` step.
69- Android SDK + emulator tooling
70- Node.js 20+ for transcript bundle builds
71 
72### Commands
73 
74From the repository root the npm scripts wrap the Gradle tasks:
 
 
 
 
 
 
75 
76```bash
77npm run android:build:transcript # build the transcript bundle
78npm run android:test:unit # ./gradlew :app:testDebugUnitTest
79npm run android:assemble:debug # ./gradlew :app:assembleDebug
80npm run android:assemble:release # ./gradlew :app:assembleRelease
81npm run android:bundle:release # ./gradlew :app:bundleRelease
82```
83 
84To invoke Gradle directly, point `JAVA_HOME` at a Temurin 17 install (no hard-coded user path):
85 
86```bash
87cd packages/android
88JAVA_HOME=/path/to/temurin-17 ./gradlew :app:assembleDebug
89JAVA_HOME=/path/to/temurin-17 ./gradlew :app:testDebugUnitTest
90```
91 
92### Play Store screenshots and video
93 
94`npm run android:screenshots` and `npm run android:walkthrough` drive an emulator against the debug-only screenshot mode in `app/src/debug/java/com/nimbalyst/app/screenshots/` (inert stub in `app/src/release/`). Never move that code into `src/main` — it seeds demo data and a fake paired state. See [ANDROID_MARKETING_SCREENSHOTS.md](../../docs/ANDROID_MARKETING_SCREENSHOTS.md).
 
95 
96### Builds, signing, and CI
97 
98- The `google-services` plugin is applied only when `app/google-services.json` is present, so a build without it succeeds and push stays inert until the file is added.
99- CI can inject Firebase config from the optional `ANDROID_GOOGLE_SERVICES_JSON_BASE64` GitHub secret by decoding it to `app/google-services.json` before the Gradle build.
100- The release `signingConfig` reads the keystore path and credentials from environment variables: `NIMBALYST_ANDROID_KEYSTORE`, `NIMBALYST_ANDROID_KEYSTORE_PASSWORD`, `NIMBALYST_ANDROID_KEY_ALIAS`, `NIMBALYST_ANDROID_KEY_PASSWORD`. When the keystore is absent the release build is simply unsigned. Minification stays off (signed is not the same as minified).
101- CI builds both the APK and Play-ready AAB via `.github/workflows/android-build.yml`, which supplies the keystore and signing secrets to produce signed release artifacts when secrets are present. CI also decodes `google-services.json` from the `ANDROID_GOOGLE_SERVICES_JSON_BASE64` secret and fails a signed build if that secret is missing, so a signed AAB never ships with push silently inert.
102- To build a signed release locally, run `npm run android:bundle:signed` (wraps `scripts/android-bundle-signed.sh`). It pulls all signing secrets from the 1Password item `Nimbalyst Android Signing` (Nimbalyst vault) at build time via `op read`: the upload keystore is fetched to a temp file deleted on exit, and passwords/alias are injected into the Gradle env only. Never commit a keystore — `*.jks`/`*.keystore` are gitignored.
103 
104Open `packages/android/` in Android Studio, not the repo root.
 
 
105 
106## Agent Guidance
107 
108- Read the root `CLAUDE.md` before changing this package.
109- Prefer following iOS behavior and naming when implementing cross-platform mobile features.
110- Do not commit secrets or local machine config such as:
111 - `app/google-services.json`
112 - `local.properties`
113 - build outputs
114- If Android Studio reports AGP incompatibility, the correct fix is usually to update Android Studio rather than downgrade AGP/Kotlin.
115- When changing sync protocol behavior, inspect the matching iOS code paths in this repo and the collab server code paths in the sibling `nimbalyst-collab` repository before editing.
116- When changing transcript bridge behavior, update or add Android tests in `app/src/test/` where possible.
117 
118## Important Files
 
 
 
119 
120| File | Purpose |
121| --- | --- |
122| `app/src/main/java/com/nimbalyst/app/NimbalystApplication.kt` | App-level dependency setup and startup wiring |
123| `app/src/main/java/com/nimbalyst/app/MainActivity.kt` | Activity entry point and deep-link handling |
124| `app/src/main/java/com/nimbalyst/app/ui/NimbalystAndroidApp.kt` | Root Compose app shell and navigation |
125| `app/src/main/java/com/nimbalyst/app/sync/SyncManager.kt` | Core mobile sync lifecycle and message handling |
126| `app/src/main/java/com/nimbalyst/app/sync/SyncProtocol.kt` | Android wire protocol types |
127| `app/src/main/java/com/nimbalyst/app/crypto/CryptoManager.kt` | Encryption and key derivation |
128| `app/src/main/java/com/nimbalyst/app/data/NimbalystDatabase.kt` | Room database definition |
129| `app/src/main/java/com/nimbalyst/app/transcript/TranscriptWebView.kt` | WebView transcript host |
130| `app/src/main/java/com/nimbalyst/app/transcript/TranscriptBridge.kt` | JS/native bridge handler |
131| `src/transcript/main.tsx` | Shared transcript app entry point for Android |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132 
nimbalyst/nimbalyst · packages/electron/CLAUDE.md
@@ +1 @@
1# Electron Package
2 
3The Nimbalyst desktop app, built with Electron.
4 
5## Development Commands
6 
7- **Dev server**: `npm run dev` (user runs this — don't do it yourself)
8- **Dev with restart loop**: `npm run dev:loop` (enables restart button / `/restart` command)
9- **Build for Mac**: `npm run build:mac:local` or `npm run build:mac:notarized`
10- **Auth callbacks in dev**: no URL-handler setup is required, including for `npm run dev:user2`. Every sign-in flow uses a nonce-protected one-shot listener on `127.0.0.1` owned by the instance that started it.
11- **Other deep links in dev (macOS)**: `npm run dev:url-handler` (from the repo root) points non-auth `nimbalyst://` links at this checkout. The applet in `scripts/install-dev-url-handler.sh` is not part of authentication. The dev app deliberately does *not* claim the scheme itself because all development copies share Electron's `com.github.Electron` bundle id. See `src/main/utils/protocolRegistration.ts`.
12 
13### Testing
 
 
 
 
14 
15From the repository root:
16- Run one spec: `npx playwright test e2e/monaco/file-watcher-updates.spec.ts`
17- Run a directory: `npx playwright test e2e/monaco/`
18- Run all: `npx playwright test`
19 
20**Always use `npx playwright test` directly.** Never use parallel execution — it corrupts PGLite. See [/docs/E2E_TESTING.md](/docs/E2E_TESTING.md).
21 
22## Architecture
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23 
24### Main and Renderer Processes
25 
26Electron apps split into two contexts:
27- **Main** runs Node.js, manages lifecycle, windows, menus, system interactions.
28- **Renderer** runs in a Chromium context; UI only.
29 
30Renderers cannot access Node.js APIs directly — use IPC to request main-process services. For initialization rules (dynamic import in `bootstrap.ts`, lazy init for `app.getPath()` consumers, `safeHandle` / `safeOn`), and cross-platform code patterns, see [MAIN_PROCESS_INIT.md](./MAIN_PROCESS_INIT.md).
 
 
31 
32## IPC Communication
33 
34### Preload API
35- **Location**: `src/preload/index.ts`
36- **Exposed as**: `window.electronAPI` (NOT `window.api`)
37- **Generic methods**: `invoke`, `send`, `on` (returns an unsubscribe closure — there is no `off`, see [/docs/IPC_LISTENERS.md](/docs/IPC_LISTENERS.md))
38- Renderer services use these to talk to main-process services.
39 
40### Document Service
41- Main: `ElectronDocumentService` (file scanning, metadata extraction, caching)
42- Renderer: `RendererDocumentService` (facade over IPC)
43- **Metadata**: frontmatter extraction with bounded reads (4KB)
44- **Channels**: `document-service:*`
45 
46### Common IPC Issues
47- `window.api undefined` → use `window.electronAPI`
48- Empty responses → check the window has a valid workspace path
49- Service resolution is keyed off workspace path
50 
51For deep IPC patterns (`safeHandle`/`safeOn`, error handling, channel structure), see [/docs/IPC_GUIDE.md](/docs/IPC_GUIDE.md).
52 
53## Data Persistence
 
 
54 
55The app runs over **either PGLite (PostgreSQL in WebAssembly) or better-sqlite3** — both backends are active during the in-progress migration. Code must work on either; do not assume one. **Never use `localStorage` in the renderer.** Persist via IPC to main using:
56- **app-settings store** (`src/main/utils/store.ts`) for global app settings
57- **workspace-settings store** for per-project state
58- **AppDatabase** (PGLite or SQLite, selected at init) for complex data (AI sessions, document history, trackers)
59 
60The biggest divergence to remember: `data->'key'` returns a parsed object on PGLite but a JSON string on SQLite. For tables, locations, shutdown rules, timestamp handling, and the full list of backend-divergent behaviors, see [DATABASE.md](./DATABASE.md).
61 
62## Renderer State Architecture
 
 
 
63 
64The renderer uses Jotai for state that crosses component boundaries. Editors use **EditorHost** — a stable service object — for all host communication; content state lives in the editor, not parent components.
65 
66| Domain | Atoms | Owner |
67| --- | --- | --- |
68| Theme | `themeAtom` | Global, IPC-synced |
69| Editors | `editorDirtyAtom(key)`, `editorProcessingAtom(key)` | EditorHost writes, Tab reads |
70| Sessions | `sessionUnreadAtom(id)`, `sessionProcessingAtom(id)` | AgenticPanel writes, UI reads |
71| File Tree | `gitStatusAtom`, `expandedDirsAtom` | WorkspaceSidebar writes, FileTree reads |
72| Trackers | `trackerCountsAtom` | TrackerService writes, UI reads |
73 
74**Re-render isolation**: parents subscribe to lists of IDs; children subscribe to their own atoms. If you need `React.memo` to prevent re-renders, you have the wrong architecture.
 
 
 
 
 
 
75 
76For full patterns, see [/docs/EDITOR_STATE.md](/docs/EDITOR_STATE.md) and [/docs/JOTAI.md](/docs/JOTAI.md).
77 
78## Logging
 
 
 
 
79 
80Three log destinations:
81 
82- **Main process log**: `~/Library/Application Support/@nimbalyst/electron/logs/main.log` — main-process events, AI, sync, file ops; categories like `(MAIN)`, `(AI)`, `(API)`, `(SYNC)`.
83- **Renderer console log** (dev mode only): `~/Library/Application Support/@nimbalyst/electron/nimbalyst-debug.log` — captured via `webContents.on('console-message')` in `src/main/index.ts`.
84 
85Use the agent log access tools (`get_main_process_logs`, `get_renderer_debug_logs`) instead of asking users to paste logs. See [/docs/DEBUGGING_LOGS.md](/docs/DEBUGGING_LOGS.md).
86 
87## Window State Persistence
 
 
 
 
88 
89- **Global session state** restores all windows on restart (bounds, focus order, dev tools state).
90- **Per-project state** restores window configuration, open file, AI panel width and collapsed state, draft inputs.
91- **Session continuity** — chat sessions persist across restarts.
92 
93## Theme Support
94 
95Themes: Light, Dark (#2d2d2d / #1a1a1a / #3a3a3a), Crystal Dark (Tailwind gray scale), Auto.
 
 
 
 
 
 
 
 
96 
97**Critical rules:**
98- Never hardcode colors in CSS files — use CSS variables.
99- `src/renderer/index.css` is the only place theme colors are defined.
100- Apply themes by setting both the `data-theme` attribute and the CSS class on the root element.
101 
102Comprehensive: [THEMING.md](./THEMING.md).
103 
104## File Operations
105 
106- **Drag-and-drop**: move files/folders in the Project Sidebar; hold Option/Alt to copy.
107- **Context menus**: rename, delete, open in new window.
108- **File watching**: auto-update on disk changes.
109 
110## AI Providers
111 
112Provider implementations live in `packages/runtime` — see `/packages/runtime/CLAUDE.md`. Electron-only pieces:
113 
114- **Renderer panels**: `src/renderer/components/AIModels/panels/ClaudePanel.tsx`, `ClaudeCodePanel.tsx`
115- **Claude Code installer**: `src/renderer/components/AIModels/services/CLIInstaller.ts` (manages local installation of `@anthropic-ai/claude-agent-sdk`)
116 
117## macOS Code Signing & Notarization
118 
119- **Certificate**: Developer ID Application
120- **Builds**: `npm run build:mac:notarized` (notarized), `build:mac:local` (local testing)
121- **Bundled tools**: ripgrep is signed; JAR files are excluded automatically (can't be notarized)
122- **Entitlements**: hardened runtime with necessary exceptions
123 
124## Git Worktree Integration
125 
126Nimbalyst creates git worktrees for isolated AI coding sessions. See [/docs/WORKTREES.md](/docs/WORKTREES.md). The `worktrees` table stores metadata; `ai_sessions.worktree_id` links sessions to worktrees. IPC channels: `worktree:create`, `worktree:get-status`, `worktree:delete`, `worktree:list`, `worktree:get`.
127 
128## Analytics
129 
130See [/docs/ANALYTICS_GUIDE.md](/docs/ANALYTICS_GUIDE.md). **When adding, modifying, or removing PostHog events, update [/docs/POSTHOG_EVENTS.md](/docs/POSTHOG_EVENTS.md).**
131 
@@ −1 +1 @@
1−# Android Package (Native Android App)
1+# Electron Package
22  
3−This package contains the native Android app for Nimbalyst. It mirrors the iOS native app architecture where practical: a pure native mobile shell with a single embedded web transcript view that renders the shared React transcript bundle.
3+The Nimbalyst desktop app, built with Electron.
44  
5−## Overview
5+## Development Commands
66  
7−The Android app is:
7+- **Dev server**: `npm run dev` (user runs this — don't do it yourself)
8+- **Dev with restart loop**: `npm run dev:loop` (enables restart button / `/restart` command)
9+- **Build for Mac**: `npm run build:mac:local` or `npm run build:mac:notarized`
10+- **Auth callbacks in dev**: no URL-handler setup is required, including for `npm run dev:user2`. Every sign-in flow uses a nonce-protected one-shot listener on `127.0.0.1` owned by the instance that started it.
11+- **Other deep links in dev (macOS)**: `npm run dev:url-handler` (from the repo root) points non-auth `nimbalyst://` links at this checkout. The applet in `scripts/install-dev-url-handler.sh` is not part of authentication. The dev app deliberately does *not* claim the scheme itself because all development copies share Electron's `com.github.Electron` bundle id. See `src/main/utils/protocolRegistration.ts`.
812  
9−- **Pure native Android** using Kotlin and Jetpack Compose
10−- **Room-backed** for local persistence
11−- **WebSocket-synced** with CollabV3 Durable Objects
12−- **End-to-end encrypted** using the same seed + user-derived key model as iOS
13−- **Transcript-rendered** through a single `WebView` that loads the bundled React transcript UI
13+### Testing
1414  
15−Voice agent features are intentionally out of scope for Android.
15+From the repository root:
16+- Run one spec: `npx playwright test e2e/monaco/file-watcher-updates.spec.ts`
17+- Run a directory: `npx playwright test e2e/monaco/`
18+- Run all: `npx playwright test`
1619  
17−## Package Structure
20+**Always use `npx playwright test` directly.** Never use parallel execution — it corrupts PGLite. See [/docs/E2E_TESTING.md](/docs/E2E_TESTING.md).
1821  
19−```text
20−packages/android/
21− app/
22− src/main/java/com/nimbalyst/app/
23− attachments/ # Image attachment preparation/compression
24− auth/ # Auth callback parsing
25− crypto/ # AES-GCM + PBKDF2 key derivation
26− data/ # Room entities, DAOs, repository
27− notifications/ # Android notification + FCM token plumbing
28− pairing/ # QR payload parsing and persistent pairing state
29− sync/ # WebSocket sync manager and wire protocol
30− transcript/ # WebView host and JS bridge
31− ui/ # Compose screens and app shell
32− src/test/ # Unit tests
33− src/transcript/ # Shared React transcript bundle entrypoint/assets
34− scripts/ # Transcript asset sync helpers
35−```
22+## Architecture
3623  
37−## Key Architecture Rules
24+### Main and Renderer Processes
3825  
39−### Transcript
26+Electron apps split into two contexts:
27+- **Main** runs Node.js, manages lifecycle, windows, menus, system interactions.
28+- **Renderer** runs in a Chromium context; UI only.
4029  
41−- The transcript UI lives in `src/transcript/main.tsx` and is bundled into Android assets.
42−- `TranscriptWebView.kt` is the Android host. `TranscriptBridge.kt` is the only place JS bridge actions should be decoded and routed.
43−- Keep transcript behavior aligned with iOS unless Android-specific UX requires a different path.
30+Renderers cannot access Node.js APIs directly — use IPC to request main-process services. For initialization rules (dynamic import in `bootstrap.ts`, lazy init for `app.getPath()` consumers, `safeHandle` / `safeOn`), and cross-platform code patterns, see [MAIN_PROCESS_INIT.md](./MAIN_PROCESS_INIT.md).
4431  
45−### Sync and Encryption
32+## IPC Communication
4633  
47−- `SyncManager.kt` owns the device sync lifecycle, room joins, index updates, queued prompt handling, and session control messages.
48−- `CryptoManager.kt` must remain wire-compatible with iOS and desktop. Be cautious with any PBKDF2, AES-GCM, or payload format changes.
49−- User routing identity and crypto identity are distinct. Do not collapse them back into a single field.
34+### Preload API
35+- **Location**: `src/preload/index.ts`
36+- **Exposed as**: `window.electronAPI` (NOT `window.api`)
37+- **Generic methods**: `invoke`, `send`, `on` (returns an unsubscribe closure — there is no `off`, see [/docs/IPC_LISTENERS.md](/docs/IPC_LISTENERS.md))
38+- Renderer services use these to talk to main-process services.
5039  
51−### Persistence
40+### Document Service
41+- Main: `ElectronDocumentService` (file scanning, metadata extraction, caching)
42+- Renderer: `RendererDocumentService` (facade over IPC)
43+- **Metadata**: frontmatter extraction with bounded reads (4KB)
44+- **Channels**: `document-service:*`
5245  
53−- Room is the source of truth for local Android UI state.
54−- Prefer repository/DAO changes over screen-local state duplication.
55−- If you add persisted fields, update schema, migrations, and any seed/demo paths together.
46+### Common IPC Issues
47+- `window.api undefined` → use `window.electronAPI`
48+- Empty responses → check the window has a valid workspace path
49+- Service resolution is keyed off workspace path
5650  
57−### Firebase / Notifications
51+For deep IPC patterns (`safeHandle`/`safeOn`, error handling, channel structure), see [/docs/IPC_GUIDE.md](/docs/IPC_GUIDE.md).
5852  
59−- `app/google-services.json` is local environment config. Do **not** commit it. The `google-services` Gradle plugin is applied conditionally (only when the file exists), so a build without it stays green and push stays inert.
60−- Client push registration lives in `notifications/NotificationManager.kt`.
61−- Server push delivery lives in the collab server, which is the sibling `nimbalyst-collab` repository, not this monorepo. Clone it next to this repo at `../nimbalyst-collab` (override with `COLLAB_SERVER_PATH`); collab tests are gated by `RUN_COLLAB_TESTS=1`. See `.github/workflows/ci.yml`. Android push changes usually require coordinated client + server work.
53+## Data Persistence
6254  
63−## Development
55+The app runs over **either PGLite (PostgreSQL in WebAssembly) or better-sqlite3** — both backends are active during the in-progress migration. Code must work on either; do not assume one. **Never use `localStorage` in the renderer.** Persist via IPC to main using:
56+- **app-settings store** (`src/main/utils/store.ts`) for global app settings
57+- **workspace-settings store** for per-project state
58+- **AppDatabase** (PGLite or SQLite, selected at init) for complex data (AI sessions, document history, trackers)
6459  
65−### Prerequisites
60+The biggest divergence to remember: `data->'key'` returns a parsed object on PGLite but a JSON string on SQLite. For tables, locations, shutdown rules, timestamp handling, and the full list of backend-divergent behaviors, see [DATABASE.md](./DATABASE.md).
6661  
67−- Android Studio Ladybug / AGP-compatible version for this project
68−- JDK 17 for Gradle builds. The project targets `JavaVersion.VERSION_17` and `jvmTarget = "17"`, and Temurin 17 matches CI. A non-17 JDK (e.g. GraalVM) can fail the AGP `jlink` step.
69−- Android SDK + emulator tooling
70−- Node.js 20+ for transcript bundle builds
62+## Renderer State Architecture
7163  
72−### Commands
64+The renderer uses Jotai for state that crosses component boundaries. Editors use **EditorHost** — a stable service object — for all host communication; content state lives in the editor, not parent components.
7365  
74−From the repository root the npm scripts wrap the Gradle tasks:
66+| Domain | Atoms | Owner |
67+| --- | --- | --- |
68+| Theme | `themeAtom` | Global, IPC-synced |
69+| Editors | `editorDirtyAtom(key)`, `editorProcessingAtom(key)` | EditorHost writes, Tab reads |
70+| Sessions | `sessionUnreadAtom(id)`, `sessionProcessingAtom(id)` | AgenticPanel writes, UI reads |
71+| File Tree | `gitStatusAtom`, `expandedDirsAtom` | WorkspaceSidebar writes, FileTree reads |
72+| Trackers | `trackerCountsAtom` | TrackerService writes, UI reads |
7573  
76−```bash
77−npm run android:build:transcript # build the transcript bundle
78−npm run android:test:unit # ./gradlew :app:testDebugUnitTest
79−npm run android:assemble:debug # ./gradlew :app:assembleDebug
80−npm run android:assemble:release # ./gradlew :app:assembleRelease
81−npm run android:bundle:release # ./gradlew :app:bundleRelease
82−```
74+**Re-render isolation**: parents subscribe to lists of IDs; children subscribe to their own atoms. If you need `React.memo` to prevent re-renders, you have the wrong architecture.
8375  
84−To invoke Gradle directly, point `JAVA_HOME` at a Temurin 17 install (no hard-coded user path):
76+For full patterns, see [/docs/EDITOR_STATE.md](/docs/EDITOR_STATE.md) and [/docs/JOTAI.md](/docs/JOTAI.md).
8577  
86−```bash
87−cd packages/android
88−JAVA_HOME=/path/to/temurin-17 ./gradlew :app:assembleDebug
89−JAVA_HOME=/path/to/temurin-17 ./gradlew :app:testDebugUnitTest
90−```
78+## Logging
9179  
92−### Play Store screenshots and video
80+Three log destinations:
9381  
94−`npm run android:screenshots` and `npm run android:walkthrough` drive an emulator against the debug-only screenshot mode in `app/src/debug/java/com/nimbalyst/app/screenshots/` (inert stub in `app/src/release/`). Never move that code into `src/main` — it seeds demo data and a fake paired state. See [ANDROID_MARKETING_SCREENSHOTS.md](../../docs/ANDROID_MARKETING_SCREENSHOTS.md).
82+- **Main process log**: `~/Library/Application Support/@nimbalyst/electron/logs/main.log` — main-process events, AI, sync, file ops; categories like `(MAIN)`, `(AI)`, `(API)`, `(SYNC)`.
83+- **Renderer console log** (dev mode only): `~/Library/Application Support/@nimbalyst/electron/nimbalyst-debug.log` — captured via `webContents.on('console-message')` in `src/main/index.ts`.
9584  
96−### Builds, signing, and CI
85+Use the agent log access tools (`get_main_process_logs`, `get_renderer_debug_logs`) instead of asking users to paste logs. See [/docs/DEBUGGING_LOGS.md](/docs/DEBUGGING_LOGS.md).
9786  
98−- The `google-services` plugin is applied only when `app/google-services.json` is present, so a build without it succeeds and push stays inert until the file is added.
99−- CI can inject Firebase config from the optional `ANDROID_GOOGLE_SERVICES_JSON_BASE64` GitHub secret by decoding it to `app/google-services.json` before the Gradle build.
100−- The release `signingConfig` reads the keystore path and credentials from environment variables: `NIMBALYST_ANDROID_KEYSTORE`, `NIMBALYST_ANDROID_KEYSTORE_PASSWORD`, `NIMBALYST_ANDROID_KEY_ALIAS`, `NIMBALYST_ANDROID_KEY_PASSWORD`. When the keystore is absent the release build is simply unsigned. Minification stays off (signed is not the same as minified).
101−- CI builds both the APK and Play-ready AAB via `.github/workflows/android-build.yml`, which supplies the keystore and signing secrets to produce signed release artifacts when secrets are present. CI also decodes `google-services.json` from the `ANDROID_GOOGLE_SERVICES_JSON_BASE64` secret and fails a signed build if that secret is missing, so a signed AAB never ships with push silently inert.
102−- To build a signed release locally, run `npm run android:bundle:signed` (wraps `scripts/android-bundle-signed.sh`). It pulls all signing secrets from the 1Password item `Nimbalyst Android Signing` (Nimbalyst vault) at build time via `op read`: the upload keystore is fetched to a temp file deleted on exit, and passwords/alias are injected into the Gradle env only. Never commit a keystore — `*.jks`/`*.keystore` are gitignored.
87+## Window State Persistence
10388  
104−Open `packages/android/` in Android Studio, not the repo root.
89+- **Global session state** restores all windows on restart (bounds, focus order, dev tools state).
90+- **Per-project state** restores window configuration, open file, AI panel width and collapsed state, draft inputs.
91+- **Session continuity** — chat sessions persist across restarts.
10592  
106−## Agent Guidance
93+## Theme Support
10794  
108−- Read the root `CLAUDE.md` before changing this package.
109−- Prefer following iOS behavior and naming when implementing cross-platform mobile features.
110−- Do not commit secrets or local machine config such as:
111− - `app/google-services.json`
112− - `local.properties`
113− - build outputs
114−- If Android Studio reports AGP incompatibility, the correct fix is usually to update Android Studio rather than downgrade AGP/Kotlin.
115−- When changing sync protocol behavior, inspect the matching iOS code paths in this repo and the collab server code paths in the sibling `nimbalyst-collab` repository before editing.
116−- When changing transcript bridge behavior, update or add Android tests in `app/src/test/` where possible.
95+Themes: Light, Dark (#2d2d2d / #1a1a1a / #3a3a3a), Crystal Dark (Tailwind gray scale), Auto.
11796  
118−## Important Files
97+**Critical rules:**
98+- Never hardcode colors in CSS files — use CSS variables.
99+- `src/renderer/index.css` is the only place theme colors are defined.
100+- Apply themes by setting both the `data-theme` attribute and the CSS class on the root element.
119101  
120−| File | Purpose |
121−| --- | --- |
122−| `app/src/main/java/com/nimbalyst/app/NimbalystApplication.kt` | App-level dependency setup and startup wiring |
123−| `app/src/main/java/com/nimbalyst/app/MainActivity.kt` | Activity entry point and deep-link handling |
124−| `app/src/main/java/com/nimbalyst/app/ui/NimbalystAndroidApp.kt` | Root Compose app shell and navigation |
125−| `app/src/main/java/com/nimbalyst/app/sync/SyncManager.kt` | Core mobile sync lifecycle and message handling |
126−| `app/src/main/java/com/nimbalyst/app/sync/SyncProtocol.kt` | Android wire protocol types |
127−| `app/src/main/java/com/nimbalyst/app/crypto/CryptoManager.kt` | Encryption and key derivation |
128−| `app/src/main/java/com/nimbalyst/app/data/NimbalystDatabase.kt` | Room database definition |
129−| `app/src/main/java/com/nimbalyst/app/transcript/TranscriptWebView.kt` | WebView transcript host |
130−| `app/src/main/java/com/nimbalyst/app/transcript/TranscriptBridge.kt` | JS/native bridge handler |
131−| `src/transcript/main.tsx` | Shared transcript app entry point for Android |
102+Comprehensive: [THEMING.md](./THEMING.md).
103+ 
104+## File Operations
105+ 
106+- **Drag-and-drop**: move files/folders in the Project Sidebar; hold Option/Alt to copy.
107+- **Context menus**: rename, delete, open in new window.
108+- **File watching**: auto-update on disk changes.
109+ 
110+## AI Providers
111+ 
112+Provider implementations live in `packages/runtime` — see `/packages/runtime/CLAUDE.md`. Electron-only pieces:
113+ 
114+- **Renderer panels**: `src/renderer/components/AIModels/panels/ClaudePanel.tsx`, `ClaudeCodePanel.tsx`
115+- **Claude Code installer**: `src/renderer/components/AIModels/services/CLIInstaller.ts` (manages local installation of `@anthropic-ai/claude-agent-sdk`)
116+ 
117+## macOS Code Signing & Notarization
118+ 
119+- **Certificate**: Developer ID Application
120+- **Builds**: `npm run build:mac:notarized` (notarized), `build:mac:local` (local testing)
121+- **Bundled tools**: ripgrep is signed; JAR files are excluded automatically (can't be notarized)
122+- **Entitlements**: hardened runtime with necessary exceptions
123+ 
124+## Git Worktree Integration
125+ 
126+Nimbalyst creates git worktrees for isolated AI coding sessions. See [/docs/WORKTREES.md](/docs/WORKTREES.md). The `worktrees` table stores metadata; `ai_sessions.worktree_id` links sessions to worktrees. IPC channels: `worktree:create`, `worktree:get-status`, `worktree:delete`, `worktree:list`, `worktree:get`.
127+ 
128+## Analytics
129+ 
130+See [/docs/ANALYTICS_GUIDE.md](/docs/ANALYTICS_GUIDE.md). **When adding, modifying, or removing PostHog events, update [/docs/POSTHOG_EVENTS.md](/docs/POSTHOG_EVENTS.md).**
132131  
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack