# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview This repository holds PulseWeaver's heartbeat clients: the **PulseWeaver Companion** app (Kotlin Multiplatform), a Docker container, and a DIY `curl` recipe. This codebase is the Companion app — a Kotlin Multiplatform app that keeps devices authorized on a PulseWeaver server by sending periodic `POST /api/v1/heartbeat` requests. Single core feature; everything else (scheduling, network-aware retries, biometric lock, system tray) is usability around that. ("Heartbeat" is the technical concept and endpoint; "PulseWeaver Companion" is the app's display name — see workspace ADR-008.) ## Commands All commands run from the repo root. Requires **JDK 17+** (Android builds also need the Android SDK). ### Build & Run - `./gradlew shared:run` — run desktop app (current OS) - `./gradlew androidApp:assembleDebug` — build Android debug APK - `PW_DEBUG=1 PW_INTERVAL=5 ./gradlew shared:run` — desktop app in debug mode: verbose logs to stderr + `~/Library/Logs/PulseWeaver/companion.log`, and a short heartbeat interval so a live beat is observable in seconds (debug-only; ignored without `PW_DEBUG`) ### Verify - `make lint` — ktlint over every source set (**not** top-level `ktlintCheck`, which fails on generated Compose resource collectors) - `make test` — JVM tests (unit + compose UI tests) - `make verify-all` — compile all targets (jvm + android + ios) + JVM tests - `make check` — `lint` + `test` These Makefile targets are sandbox-safe. Ad-hoc `./gradlew` fails under the Claude Code sandbox on the Kotlin daemon's temp file — see the workspace pattern `docs/patterns/kotlin-multiplatform/testing.md` for the known-good invocation. - `./gradlew ktlintFormat` — auto-fix code style (top-level format is safe) ### Package - `./gradlew shared:packageDmg` — macOS installer - `./gradlew shared:packageMsi` — Windows installer - `./gradlew shared:packageDeb` — Linux .deb ## Architecture Kotlin Multiplatform with Compose Multiplatform UI. Two Gradle modules: - **`:shared`** — all application code (common + platform source sets) - **`:androidApp`** — thin Android entry point wrapping `:shared` ### Source sets (`shared/src/`) | Source set | Purpose | |---|---| | `commonMain` | UI, business logic, HTTP client, config — the bulk of the app | | `androidMain` | Alarm-chain scheduler, network callbacks, biometric auth, Android config store | | `jvmMain` | Desktop entry point, system tray, JVM timer scheduler | | `iosMain` | iOS HTTP engine (Ktor Darwin) | | `commonTest` | Unit tests, Ktor MockEngine tests, compose UI tests | | `jvmTest` | Desktop-specific test support | ### Key packages (`com.pulseweaver.heartbeat`) | Package | What it contains | |---|---| | `service/` | `HeartbeatClient` (Ktor HTTP), result types | | `config/` | `HeartbeatConfig` data class, `ConfigStore` expect/actual | | `platform/` | `BackgroundScheduler`, `NetworkMonitor`, `BiometricAuth` (expect/actual) | | `ui/` | Compose screens (`HeartbeatScreen`, `AuthGate`) | ### Tech stack - Kotlin 2.4.10, Compose Multiplatform 1.11.1, Ktor 3.5.2 - Version catalog: `gradle/libs.versions.toml` - Code style: ktlint ## Conventions - **expect/actual** for platform abstractions — keep `commonMain` as the default working location - Tests use Ktor `MockEngine` for HTTP and `compose-ui-test` for UI - Keep the app simple: one feature (heartbeat), minimal surface area