diff --git a/README.md b/README.md
index 601f945..c9f4a15 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,17 @@ docker run -p 3000:3000 ruvnet/wifi-densepose:latest
---
+## π Documentation
+
+| Document | Description |
+|----------|-------------|
+| [User Guide](docs/user-guide.md) | Step-by-step guide: installation, first run, API usage, hardware setup, training |
+| [WiFi-Mat User Guide](docs/wifi-mat-user-guide.md) | Disaster response module: search & rescue, START triage |
+| [Build Guide](docs/build-guide.md) | Building from source (Rust and Python) |
+| [Architecture Decisions](docs/adr/) | 24 ADRs covering signal processing, training, hardware, security |
+
+---
+
## π Key Features
| | Feature | What It Means |
@@ -317,6 +328,44 @@ docker run --rm -v $(pwd):/out ruvnet/wifi-densepose:latest --export-rvf /out/mo
+
+Rust Crates β Individual crates on crates.io
+
+The Rust workspace consists of 14 crates, all published to [crates.io](https://crates.io/):
+
+```bash
+# Add individual crates to your Cargo.toml
+cargo add wifi-densepose-core # Types, traits, errors
+cargo add wifi-densepose-signal # CSI signal processing (6 SOTA algorithms)
+cargo add wifi-densepose-nn # Neural inference (ONNX, PyTorch, Candle)
+cargo add wifi-densepose-vitals # Vital sign extraction (breathing + heart rate)
+cargo add wifi-densepose-mat # Disaster response (MAT survivor detection)
+cargo add wifi-densepose-hardware # ESP32, Intel 5300, Atheros sensors
+cargo add wifi-densepose-train # Training pipeline (MM-Fi dataset)
+cargo add wifi-densepose-wifiscan # Multi-BSSID WiFi scanning
+```
+
+| Crate | Description | RuVector | crates.io |
+|-------|-------------|----------|-----------|
+| [`wifi-densepose-core`](https://crates.io/crates/wifi-densepose-core) | Foundation types, traits, and utilities | -- | [](https://crates.io/crates/wifi-densepose-core) |
+| [`wifi-densepose-signal`](https://crates.io/crates/wifi-densepose-signal) | SOTA CSI signal processing (SpotFi, FarSense, Widar 3.0) | `mincut`, `attn-mincut`, `attention`, `solver` | [](https://crates.io/crates/wifi-densepose-signal) |
+| [`wifi-densepose-nn`](https://crates.io/crates/wifi-densepose-nn) | Multi-backend inference (ONNX, PyTorch, Candle) | -- | [](https://crates.io/crates/wifi-densepose-nn) |
+| [`wifi-densepose-train`](https://crates.io/crates/wifi-densepose-train) | Training pipeline with MM-Fi dataset (NeurIPS 2023) | **All 5** | [](https://crates.io/crates/wifi-densepose-train) |
+| [`wifi-densepose-mat`](https://crates.io/crates/wifi-densepose-mat) | Mass Casualty Assessment Tool (disaster survivor detection) | `solver`, `temporal-tensor` | [](https://crates.io/crates/wifi-densepose-mat) |
+| [`wifi-densepose-vitals`](https://crates.io/crates/wifi-densepose-vitals) | Vital signs: breathing (6-30 BPM), heart rate (40-120 BPM) | -- | [](https://crates.io/crates/wifi-densepose-vitals) |
+| [`wifi-densepose-hardware`](https://crates.io/crates/wifi-densepose-hardware) | ESP32, Intel 5300, Atheros CSI sensor interfaces | -- | [](https://crates.io/crates/wifi-densepose-hardware) |
+| [`wifi-densepose-wifiscan`](https://crates.io/crates/wifi-densepose-wifiscan) | Multi-BSSID WiFi scanning (Windows-enhanced) | -- | [](https://crates.io/crates/wifi-densepose-wifiscan) |
+| [`wifi-densepose-wasm`](https://crates.io/crates/wifi-densepose-wasm) | WebAssembly bindings for browser deployment | -- | [](https://crates.io/crates/wifi-densepose-wasm) |
+| [`wifi-densepose-sensing-server`](https://crates.io/crates/wifi-densepose-sensing-server) | Axum server: UDP ingestion, WebSocket broadcast | -- | [](https://crates.io/crates/wifi-densepose-sensing-server) |
+| [`wifi-densepose-cli`](https://crates.io/crates/wifi-densepose-cli) | Command-line tool for MAT disaster scanning | -- | [](https://crates.io/crates/wifi-densepose-cli) |
+| [`wifi-densepose-api`](https://crates.io/crates/wifi-densepose-api) | REST + WebSocket API layer | -- | [](https://crates.io/crates/wifi-densepose-api) |
+| [`wifi-densepose-config`](https://crates.io/crates/wifi-densepose-config) | Configuration management | -- | [](https://crates.io/crates/wifi-densepose-config) |
+| [`wifi-densepose-db`](https://crates.io/crates/wifi-densepose-db) | Database persistence (PostgreSQL, SQLite, Redis) | -- | [](https://crates.io/crates/wifi-densepose-db) |
+
+All crates integrate with [RuVector v2.0.4](https://github.com/ruvnet/ruvector) for graph algorithms and neural network optimization.
+
+
+
---
## π Quick Start
@@ -548,8 +597,8 @@ cargo bench --package wifi-densepose-signal
| **Confidence** | 0.0-1.0 per sign | Spectral coherence + signal quality |
```bash
-./target/release/sensing-server --source simulate --ui-path ../../ui
-curl http://localhost:8080/api/v1/vital-signs
+./target/release/sensing-server --source simulate --http-port 3000 --ws-port 3001 --ui-path ../../ui
+curl http://localhost:3000/api/v1/vital-signs
```
See [ADR-021](docs/adr/ADR-021-vital-sign-detection-rvdna-pipeline.md).
@@ -1026,9 +1075,9 @@ GET /api/v1/model/sona/profiles # SONA profiles
POST /api/v1/model/sona/activate # Activate SONA profile
```
-WebSocket: `ws://localhost:8765/ws/sensing` (real-time sensing + vital signs)
+WebSocket: `ws://localhost:3001/ws/sensing` (real-time sensing + vital signs)
-> Default ports: HTTP 8080, WS 8765. Docker images remap to 3000/3001 via `--http-port` / `--ws-port`.
+> Default ports (Docker): HTTP 3000, WS 3001. Binary defaults: HTTP 8080, WS 8765. Override with `--http-port` / `--ws-port`.
diff --git a/docs/adr/ADR-025-macos-corewlan-wifi-sensing.md b/docs/adr/ADR-025-macos-corewlan-wifi-sensing.md
new file mode 100644
index 0000000..491ecea
--- /dev/null
+++ b/docs/adr/ADR-025-macos-corewlan-wifi-sensing.md
@@ -0,0 +1,315 @@
+# ADR-025: macOS CoreWLAN WiFi Sensing via Swift Helper Bridge
+
+| Field | Value |
+|-------|-------|
+| **Status** | Proposed |
+| **Date** | 2026-03-01 |
+| **Deciders** | ruv |
+| **Codename** | **ORCA** β OS-native Radio Channel Acquisition |
+| **Relates to** | ADR-013 (Feature-Level Sensing Commodity Gear), ADR-022 (Windows WiFi Enhanced Fidelity), ADR-014 (SOTA Signal Processing), ADR-018 (ESP32 Dev Implementation) |
+| **Issue** | [#56](https://github.com/ruvnet/wifi-densepose/issues/56) |
+| **Build/Test Target** | Mac Mini (M2 Pro, macOS 26.3) |
+
+---
+
+## 1. Context
+
+### 1.1 The Gap: macOS Is a Silent Fallback
+
+The `--source auto` path in `sensing-server` probes for ESP32 UDP, then Windows `netsh`, then falls back to simulated mode. macOS users hit the simulation path silently β there is no macOS WiFi adapter. This is the only major desktop platform without real WiFi sensing support.
+
+### 1.2 Platform Constraints (macOS 26.3+)
+
+| Constraint | Detail |
+|------------|--------|
+| **`airport` CLI removed** | Apple removed `/System/Library/PrivateFrameworks/.../airport` in macOS 15. No CLI fallback exists. |
+| **CoreWLAN is the only path** | `CWWiFiClient` (Swift/ObjC) is the supported API for WiFi scanning. Returns RSSI, channel, SSID, noise, PHY mode, security. |
+| **BSSIDs redacted** | macOS privacy policy redacts MAC addresses from `CWNetwork.bssid` unless the app has Location Services + WiFi entitlement. Apps without entitlement see `nil` for BSSID. |
+| **No raw CSI** | Apple does not expose CSI or per-subcarrier data. macOS WiFi sensing is RSSI-only, same tier as Windows `netsh`. |
+| **Scan rate** | `CWInterface.scanForNetworks()` takes ~2-4 seconds. Effective rate: ~0.3-0.5 Hz without caching. |
+| **Permissions** | Location Services prompt required for BSSID access. Without it, SSID + RSSI + channel still available. |
+
+### 1.3 The Opportunity: Multi-AP RSSI Diversity
+
+Same principle as ADR-022 (Windows): visible APs serve as pseudo-subcarriers. A typical indoor environment exposes 10-30+ SSIDs across 2.4 GHz and 5 GHz bands. Each AP's RSSI responds differently to human movement based on geometry, creating spatial diversity.
+
+| Source | Effective Subcarriers | Sample Rate | Capabilities |
+|--------|----------------------|-------------|-------------|
+| ESP32-S3 (CSI) | 56-192 | 20 Hz | Full: pose, vitals, through-wall |
+| Windows `netsh` (ADR-022) | 10-30 BSSIDs | ~2 Hz | Presence, motion, coarse breathing |
+| **macOS CoreWLAN (this ADR)** | **10-30 SSIDs** | **~0.3-0.5 Hz** | **Presence, motion** |
+
+The lower scan rate vs Windows is offset by higher signal quality β CoreWLAN returns calibrated dBm (not percentage) plus noise floor, enabling proper SNR computation.
+
+### 1.4 Why Swift Subprocess (Not FFI)
+
+| Approach | Complexity | Maintenance | Build | Verdict |
+|----------|-----------|-------------|-------|---------|
+| **Swift CLI β JSON β stdout** | Low | Independent binary, versionable | `swiftc` (ships with Xcode CLT) | **Chosen** |
+| ObjC FFI via `cc` crate | Medium | Fragile header bindings, ABI churn | Requires Xcode headers | Rejected |
+| `objc2` crate (Rust ObjC bridge) | High | CoreWLAN not in upstream `objc2-frameworks` | Requires manual class definitions | Rejected |
+| `swift-bridge` crate | High | Young ecosystem, async bridging unsupported | Requires Swift build integration in Cargo | Rejected |
+
+The `Command::new()` + parse JSON pattern is proven β it's exactly what `NetshBssidScanner` does for Windows. The subprocess boundary also isolates Apple framework dependencies from the Rust build graph.
+
+### 1.5 SOTA: Platform-Adaptive WiFi Sensing
+
+Recent work validates multi-platform RSSI-based sensing:
+
+- **WiFind** (2024): Cross-platform WiFi fingerprinting using RSSI vectors from heterogeneous hardware. Demonstrates that normalization across scan APIs (dBm, percentage, raw) is critical for model portability.
+- **WiGesture** (2025): RSSI variance-based gesture recognition achieving 89% accuracy on commodity hardware with 15+ APs. Shows that temporal RSSI variance alone carries significant motion information.
+- **CrossSense** (2024): Transfer learning from CSI-rich hardware to RSSI-only devices. Pre-trained signal features transfer with 78% effectiveness, validating multi-tier hardware strategy.
+
+---
+
+## 2. Decision
+
+Implement a **macOS CoreWLAN sensing adapter** as a Swift helper binary + Rust adapter pair, following the established `NetshBssidScanner` subprocess pattern from ADR-022. Real RSSI data flows through the existing 8-stage `WindowsWifiPipeline` (which operates on `BssidObservation` structs regardless of platform origin).
+
+### 2.1 Design Principles
+
+1. **Subprocess isolation** β Swift binary is a standalone tool, built and versioned independently of the Rust workspace.
+2. **Same domain types** β macOS adapter produces `Vec`, identical to the Windows path. All downstream processing reuses as-is.
+3. **SSID:channel as synthetic BSSID** β When real BSSIDs are redacted (no Location Services), `sha256(ssid + channel)[:12]` generates a stable pseudo-BSSID. Documented limitation: same-SSID same-channel APs collapse to one observation.
+4. **`#[cfg(target_os = "macos")]` gating** β macOS-specific code compiles only on macOS. Windows and Linux builds are unaffected.
+5. **Graceful degradation** β If the Swift helper is not found or fails, `--source auto` skips macOS WiFi and falls back to simulated mode with a clear warning.
+
+---
+
+## 3. Architecture
+
+### 3.1 Component Overview
+
+```
+βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+β macOS WiFi Sensing Path β
+β β
+β ββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββ
+β β Swift Helper Binary β β Rust Adapter + Existing Pipeline ββ
+β β (tools/macos-wifi- β β ββ
+β β scan/main.swift) β β MacosCoreWlanScanner ββ
+β β β β β ββ
+β β CWWiFiClient βJSON β βΌ ββ
+β β scanForNetworks() βββΌβββββΊβ Vec ββ
+β β interface() β β β ββ
+β β β β βΌ ββ
+β β Outputs: β β BssidRegistry ββ
+β β - ssid β β β ββ
+β β - rssi (dBm) β β βΌ ββ
+β β - noise (dBm) β β WindowsWifiPipeline (reused) ββ
+β β - channel β β [8-stage signal intelligence] ββ
+β β - band (2.4/5/6) β β β ββ
+β β - phy_mode β β βΌ ββ
+β β - bssid (if avail) β β SensingUpdate β REST/WS ββ
+β ββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββ
+βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+```
+
+### 3.2 Swift Helper Binary
+
+**File:** `rust-port/wifi-densepose-rs/tools/macos-wifi-scan/main.swift`
+
+```swift
+// Modes:
+// (no args) β Full scan, output JSON array to stdout
+// --probe β Quick availability check, output {"available": true/false}
+// --connected β Connected network info only
+//
+// Output schema (scan mode):
+// [
+// {
+// "ssid": "MyNetwork",
+// "rssi": -52,
+// "noise": -90,
+// "channel": 36,
+// "band": "5GHz",
+// "phy_mode": "802.11ax",
+// "bssid": "aa:bb:cc:dd:ee:ff" | null,
+// "security": "wpa2_personal"
+// }
+// ]
+```
+
+**Build:**
+
+```bash
+# Requires Xcode Command Line Tools (xcode-select --install)
+cd tools/macos-wifi-scan
+swiftc -framework CoreWLAN -framework Foundation -O -o macos-wifi-scan main.swift
+```
+
+**Build script:** `tools/macos-wifi-scan/build.sh`
+
+### 3.3 Rust Adapter
+
+**File:** `crates/wifi-densepose-wifiscan/src/adapter/macos_scanner.rs`
+
+```rust
+// #[cfg(target_os = "macos")]
+
+pub struct MacosCoreWlanScanner {
+ helper_path: PathBuf, // Resolved at construction: $PATH or sibling of server binary
+}
+
+impl MacosCoreWlanScanner {
+ pub fn new() -> Result // Finds helper or errors
+ pub fn probe() -> bool // Runs --probe, returns availability
+ pub fn scan_sync(&self) -> Result, WifiScanError>
+ pub fn connected_sync(&self) -> Result