{"id":50677197,"url":"https://github.com/ruvnet/rvcsi","last_synced_at":"2026-06-08T16:05:53.856Z","repository":{"id":357491030,"uuid":"1237259513","full_name":"ruvnet/rvcsi","owner":"ruvnet","description":"rvCSI — edge RF sensing runtime: normalize WiFi CSI from Nexmon/ESP32/Intel/Atheros/file/replay into one validated CsiFrame schema, run reusable DSP, emit typed confidence-scored events, bridge to RuVector. Rust + @ruv/rvcsi (npm) + rvcsi CLI + a Claude Code plugin.","archived":false,"fork":false,"pushed_at":"2026-05-13T03:04:55.000Z","size":0,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-13T03:14:01.372Z","etag":null,"topics":["channel-state-information","csi","edge-ai","esp32","nexmon","presence-detection","rf-sensing","rust","ruvector","wifi"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ruvnet.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-13T02:49:19.000Z","updated_at":"2026-05-13T03:13:25.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ruvnet/rvcsi","commit_stats":null,"previous_names":["ruvnet/rvcsi"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/ruvnet/rvcsi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruvnet%2Frvcsi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruvnet%2Frvcsi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruvnet%2Frvcsi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruvnet%2Frvcsi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ruvnet","download_url":"https://codeload.github.com/ruvnet/rvcsi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruvnet%2Frvcsi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34069526,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["channel-state-information","csi","edge-ai","esp32","nexmon","presence-detection","rf-sensing","rust","ruvector","wifi"],"created_at":"2026-06-08T16:05:51.029Z","updated_at":"2026-06-08T16:05:53.841Z","avatar_url":"https://github.com/ruvnet.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 📡 rvCSI — edge RF sensing runtime\n\n\u003e **Turn WiFi Channel State Information into validated, typed, confidence-scored RF events — in Rust, from TypeScript, from the CLI.**\n\n[![Rust 1.85+](https://img.shields.io/badge/rust-1.85+-orange.svg)](https://www.rust-lang.org/)\n[![License: MIT OR Apache-2.0](https://img.shields.io/badge/License-MIT%20OR%20Apache--2.0-blue.svg)](#license)\n[![Tests: 170](https://img.shields.io/badge/tests-170%20passed-brightgreen.svg)](#testing)\n[![crates.io](https://img.shields.io/crates/v/rvcsi-core.svg)](https://crates.io/crates/rvcsi-core)\n[![npm](https://img.shields.io/npm/v/@ruv/rvcsi.svg)](https://www.npmjs.com/package/@ruv/rvcsi)\n\nrvCSI is the **stable, hardware-abstracted runtime layer** that real CSI pipelines are missing. Today, WiFi sensing is shell scripts, patched firmware, kernel modules, Python notebooks, PCAP dumps and ad-hoc DSP — formats differ per chip, drivers are unstable, malformed packets are common, device assumptions leak everywhere. rvCSI fixes that:\n\n- **Ingests** CSI from many sources behind one trait (`CsiSource`) — Nexmon (BCM43455c0 / Raspberry Pi 4 \u0026 **5**, 4358, 4366c0), ESP32, Intel, Atheros, `.rvcsi` capture files, deterministic replay.\n- **Validates** every packet in Rust *before* it can touch application code — length/finiteness/profile checks, plausibility bounds, structured errors, never panics, never raw pointers across a language boundary.\n- **Normalizes** everything into one schema — `CsiFrame` → `CsiWindow` → `CsiEvent`.\n- **Processes** with reusable DSP — Hampel/MAD outlier filter, phase unwrap, smoothing, sliding variance, DC removal, baseline subtraction, motion energy, presence, heuristic breathing-band estimate.\n- **Emits** typed events with confidence + evidence — presence started/ended, motion detected/settled, baseline drift, anomaly, signal-quality drop, calibration-required, breathing candidate.\n- **Bridges** to [RuVector](https://github.com/ruvnet/ruvector) as RF memory — deterministic window/event embeddings, similarity search, drift detection.\n- **Exposes** a Rust API, a TypeScript SDK ([`@ruv/rvcsi`](https://www.npmjs.com/package/@ruv/rvcsi), napi-rs), and a CLI (`rvcsi`).\n\n\u003e rvCSI is *structural sensing*: excellent at detecting change, presence, motion, drift, and learned patterns — deliberately silent on exact identity, exact pose, and medical-grade certainty. **Detection ≠ decision** — rvCSI emits evidence; agents and applications decide what to do.\n\nThe architecture is set by **[ADR-095](docs/adr/ADR-095-rvcsi-edge-rf-sensing-platform.md)** (the 15 platform decisions: Rust core, C-only-at-the-hardware-boundary, TS SDK via napi-rs, normalized schema, validate-before-FFI, CSI-as-temporal-delta, RuVector as RF memory, replayability, detection≠decision, local-first, read-first/write-gated MCP, mandatory quality scoring, versioned calibration, plugin adapters) and **[ADR-096](docs/adr/ADR-096-rvcsi-ffi-crate-layout.md)** (the crate topology, the napi-c shim contract, the napi-rs surface). See the [PRD](docs/prd/rvcsi-platform-prd.md) for requirements and the [domain model](docs/ddd/rvcsi-domain-model.md) for the 7 bounded contexts.\n\n---\n\n## Crates\n\n| Crate | `unsafe`? | What it owns |\n|-------|-----------|--------------|\n| [`rvcsi-core`](crates/rvcsi-core) | no (`forbid`) | The normalized `CsiFrame`/`CsiWindow`/`CsiEvent` schema, `AdapterProfile`, the `CsiSource` plugin trait, id newtypes + `IdGenerator`, `RvcsiError`, the `validate_frame` pipeline + quality scoring. The shared kernel. |\n| [`rvcsi-dsp`](crates/rvcsi-dsp) | no (`forbid`) | Pure DSP primitives (`mean`/`variance`/`median`, `remove_dc_offset`, `unwrap_phase`, `moving_average`, `ewma`, `hampel_filter`, `short_window_variance`, `subtract_baseline`), scalar features (`motion_energy`, `presence_score`, `confidence_score`, heuristic `breathing_band_estimate`), and a non-destructive `SignalPipeline::process_frame`. |\n| [`rvcsi-events`](crates/rvcsi-events) | no (`forbid`) | `WindowBuffer` (frames → `CsiWindow`), the `EventDetector` trait + presence/motion/quality/baseline-drift state machines (drift thresholds are **scale-relative** — a fraction of the baseline magnitude — so one tuning works across `int8` ESP32, `int16`-scaled Nexmon, and baseline-subtracted streams), and `EventPipeline`. |\n| [`rvcsi-adapter-file`](crates/rvcsi-adapter-file) | no (`forbid`) | The `.rvcsi` capture container (JSONL: a header line + one `CsiFrame` per line), `FileRecorder`, `FileReplayAdapter` — deterministic replay. |\n| [`rvcsi-adapter-nexmon`](crates/rvcsi-adapter-nexmon) | **yes** (FFI only) | The **napi-c** seam: `native/rvcsi_nexmon_shim.{c,h}` (the only C in the runtime — allocation-free, bounds-checked, ABI `1.1`) compiled via `build.rs`+`cc`, handling the rvCSI Nexmon record **and** the real nexmon_csi UDP payload (18-byte header + `int16` I/Q) + a Broadcom d11ac **chanspec decoder**; a pure-Rust **libpcap reader**; a **Nexmon-chip / Raspberry-Pi-model registry** (incl. **Pi 5 → BCM43455c0**); `NexmonAdapter` + `NexmonPcapAdapter` `CsiSource`s. |\n| [`rvcsi-ruvector`](crates/rvcsi-ruvector) | no (`forbid`) | The RuVector RF-memory bridge: deterministic `window_embedding`/`event_embedding`, `cosine_similarity`, the `RfMemoryStore` trait, `InMemoryRfMemory` + `JsonlRfMemory` (standins until the production RuVector binding lands). |\n| [`rvcsi-runtime`](crates/rvcsi-runtime) | no (`forbid`) | The no-FFI composition layer: `CaptureRuntime` = `CsiSource` + `validate_frame` + `SignalPipeline` + `EventPipeline`, plus one-shot helpers (`summarize_capture`, `decode_nexmon_records`, `decode_nexmon_pcap`, `summarize_nexmon_pcap`, `events_from_capture`, `export_capture_to_rf_memory`). The shared layer under `rvcsi-node` and `rvcsi-cli`. |\n| [`rvcsi-node`](crates/rvcsi-node) | no (`deny(clippy::all)`) | The **napi-rs** seam — the `.node` addon (cdylib + rlib) exposing a safe TS-facing surface (thin `#[napi]` wrappers over `rvcsi-runtime`); ships as the [`@ruv/rvcsi`](https://www.npmjs.com/package/@ruv/rvcsi) npm package. |\n| [`rvcsi-cli`](crates/rvcsi-cli) | no | The `rvcsi` binary: `record`, `inspect`, `inspect-nexmon`, `nexmon-chips`, `decode-chanspec`, `replay`, `stream`, `events`, `health`, `calibrate`, `export ruvector`. |\n\n`rvcsi-mcp` (an MCP tool server), `rvcsi-daemon` (live radio capture + WebSocket), `rvcsi-adapter-esp32` (a live ESP32 serial/UDP source), and the legacy nexmon *packed-float* CSI export are tracked as follow-ups on top of these crates.\n\n---\n\n## Install\n\n### Rust\n\n```bash\n# the CLI\ncargo install rvcsi-cli      # installs the `rvcsi` binary\n\n# or a library, in Cargo.toml\n[dependencies]\nrvcsi-core    = \"0.3\"\nrvcsi-dsp     = \"0.3\"\nrvcsi-events  = \"0.3\"\nrvcsi-runtime = \"0.3\"        # the composition layer most apps want\n```\n\n### Node / TypeScript\n\n```bash\nnpm install @ruv/rvcsi\n```\n\n```ts\nimport { inspectCaptureFile, eventsFromCaptureFile, RvcsiRuntime } from \"@ruv/rvcsi\";\n\nconsole.log(inspectCaptureFile(\"session.rvcsi\"));        // frame count, channels, quality, ...\nfor (const ev of eventsFromCaptureFile(\"session.rvcsi\")) // presence/motion/anomaly/...\n  console.log(ev.kind, ev.confidence, ev.timestampNs);\n\nconst rt = RvcsiRuntime.openCaptureFile(\"session.rvcsi\");\nlet f; while ((f = rt.nextCleanFrameJson()) !== null) { /* validated + DSP-cleaned */ }\n```\n\n---\n\n## Quickstart (CLI)\n\n```bash\n# Capture real nexmon_csi on a Raspberry Pi:\ntcpdump -i wlan0 dst port 5500 -w csi.pcap\n\n# Transcode to a validated .rvcsi capture (Pi 5 / BCM43455c0 profile):\nrvcsi record --source nexmon-pcap --in csi.pcap --out session.rvcsi --chip pi5\n\n# Inspect it:\nrvcsi inspect session.rvcsi\n#   frames : 12048   channels : [36]   subcarriers : [256]   mean quality : 0.91\n#   validation : accepted=12001 degraded=47 rejected=0 ...\n\n# Run the DSP + event pipeline:\nrvcsi events session.rvcsi\n#   1700000000000000000 ns  presence_started   conf=0.94  evidence=[7]\n#   1700000003000000000 ns  motion_detected    conf=0.81  evidence=[10]\n#   1700000061000000000 ns  baseline_changed   conf=0.62  evidence=[31]\n\n# Learn a v0 baseline, decode a chanspec, list known Nexmon chips:\nrvcsi calibrate --in session.rvcsi --out baseline.json\nrvcsi decode-chanspec 0xe024\nrvcsi nexmon-chips\n```\n\nThere is **no ESP32 adapter crate yet** — until `rvcsi-adapter-esp32` lands, an ESP32 `.csi.jsonl` recording can be transcoded into `.rvcsi` with the bridge script in [`scripts/`](scripts/), then run through the same `inspect` / `events` / `calibrate` toolchain.\n\n---\n\n## Claude plugin\n\nThis repo ships a [Claude Code](https://claude.com/claude-code) plugin marketplace ([`.claude-plugin/marketplace.json`](.claude-plugin/marketplace.json)) with an **`rvcsi`** plugin: slash commands for capturing/inspecting/replaying CSI and running the event pipeline, plus an agent that knows the schema, the validation rules, and the adapter contract.\n\n```\n/plugin marketplace add ruvnet/rvcsi\n/plugin install rvcsi@rvcsi\n```\n\nThen: `/rvcsi-inspect \u003cfile.rvcsi\u003e`, `/rvcsi-events \u003cfile.rvcsi\u003e`, `/rvcsi-record …`, `/rvcsi-nexmon …`. See [`plugins/rvcsi/README.md`](plugins/rvcsi/README.md).\n\n---\n\n## Build \u0026 test\n\n```bash\ncargo build --workspace\ncargo test  --workspace          # 170 tests, 0 failures\ncargo clippy --workspace         # clippy-clean\n```\n\n`#![forbid(unsafe_code)]` in every crate except `rvcsi-adapter-nexmon`, where `unsafe` is confined to one `ffi` module wrapping the C shim — every block carries a `// SAFETY:` comment. The C shim is allocation-free, bounds-checked, ABI-versioned, and never panics.\n\n`rvcsi-node` is a workspace member (a napi cdylib links fine with Node symbols left undefined on Linux/macOS), so `cargo build`/`cargo test` work without a Node toolchain — only `napi build` (the npm prebuild) needs Node.\n\n---\n\n## Provenance\n\nrvCSI was extracted from the [RuView / WiFi-DensePose](https://github.com/ruvnet/RuView) project (ADR-095, ADR-096) where it was incubated; RuView consumes it back as a `vendor/rvcsi` submodule.\n\n## License\n\nLicensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT license](LICENSE-MIT) at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruvnet%2Frvcsi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fruvnet%2Frvcsi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruvnet%2Frvcsi/lists"}