announce: @claude-flow/guidance 2.70x retrieval speedup + 32x memory reduction via 1-bit quantization
- Dominant language
- TypeScript
- Stars
- 72.7k
- Forks
- 8.6k
- Avg merge
- 2d 23h
- Merged PRs (30d)
- 83
Description
**Released in 3.7.0-alpha.79.** The `@claude-flow/guidance` retriever now uses RaBitQ-style 1-bit-per-dim signatures + Hamming popcount, replacing the per-pair Float32 cosine on the hot path. All 1,331 existing tests pass.
## Headline numbers
| Metric | Baseline | **alpha.79** | Speedup |
|--------|---------:|-------------:|--------:|
| `retriever.retrieve()` at N=100 shards | 12,135 ops/s | 26,372 ops/s | **2.17x** |
| `retriever.retrieve()` at N=500 shards | 2,470 ops/s | 6,468 ops/s | **2.62x** |
| `retriever.retrieve()` at N=1000 shards | 1,303 ops/s | 3,522 ops/s | 🚀 **2.70x** |
| Memory per shard signature | 1,536 bytes | **48 bytes** | **32x smaller** |
| Per-pair Hamming vs Float32 dot | 332 ns | 30 ns | **10.93x** |
At N=10,000 shards: index footprint drops from 15.0 MB → 480 KB. For hooks-running daemons doing cold-start retrieval, this is real.
## What changed
The hot path in `ShardRetriever.scoreShards` (used by every `hooks pre-task` / `pre-edit` lookup) now computes cosine approximation via:
1. For each unit-normalized embedding, record the **sign of each dimension** as a 1-bit signature
2. Pack into Uint32 words — `dim=384 → 12 words = 48 bytes`
3. Query-time: XOR the signatures, popcount the result → Hamming distance
4. Approximate cosine via the **Sign-Random-Projection theorem** (Charikar 2002):
> `cos(θ) ≈ cos(π · hamming(sig_q, sig_s) / dim)`
The full Float32 path still exists as a fallback (when shard count <100 or dims don't match) — quantization fires only when the constant-factor signature build amortises.
## Try it
```bash
npx ruflo@3.7.0-alpha.79 init
# or upgrade in place
npm i -g ruflo@latest
```
## Reproduce the benchmarks
```bash
git clone https://github.com/ruvnet/ruflo
cd ruflo/v3/@claude-flow/guidance
npm install && npm run build
node scripts/bench-retriever-scale.mjs --tag=verify
node scripts/bench-quantization.mjs --tag=verify
```
All benchmarks are deterministic (mulberry32-seeded fixtures), 5-trial median, reproducible at ±2%.
## Related artifacts
- 🔗 **Public gist with full numbers + iteration log**: https://gist.github.com/ruvnet/fcf31c97644acb3cb001f8fdfb4c25f4
- 🔗 **PR #2103**: https://github.com/ruvnet/ruflo/pull/2103
- 📊 **Benchmark JSON artifacts**: `docs/benchmarks/guidance-*.json` (8 files captured)
## Why this works where micro-tuning didn't
The first two iterations on this branch attacked V8 JIT-friendly hot paths (`.filter()` chains, regex literals, sqrt math). The JIT already optimised them — manual unrolling delivered within-noise improvements. The real win came from the **algorithmic change**: 384 multiplies replaced with 12 XOR + popcount per pair (~11x at the per-pair granularity, amortised to 2.7x end-to-end via Amdahl on the non-cosine work).
## Deferred (next ADRs)
- **Two-stage retrieval**: M4 Hamming for coarse top-K shortlist + exact Float32 cosine on survivors. Recovers full accuracy while keeping most of the speedup.
- **True HNSW** for O(log n) per query (separate ADR, requires graph sidecar).
- **dim=768+ embeddings**: the quantization speedup grows with dim — at dim=1536 (modern SOTA) the per-pair Hamming win approaches 20-30x.
— rUv
Contributor guide
Research direction
Read PR #2103 and the release details for the completed retriever change. From v3/@claude-flow/guidance, install dependencies and run scripts/bench-retriever-scale.mjs and scripts/bench-quantization.mjs with the verify tag. Done means reproducing the reported benchmark results and documenting any discrepancy.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- performance
- Issue type
- Documentation
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 15/100