Compare commits

..

3 Commits

Author SHA1 Message Date
Claude b4a739402b fix: Correct rfft array size calculation in vital signs detection
Fixed IndexError in breathing and heartbeat detection caused by incorrect
rfft output length calculation. The rfft output length is n//2+1 for input
of length n, so original length is (len(spectrum)-1)*2, not len(spectrum)*2.

Also added array length alignment to prevent edge case dimension mismatches.
2026-01-14 18:33:28 +00:00
Claude 2ca107c10c feat: Make Python implementation real - remove random data generators
Major refactoring to replace placeholder/mock implementations with real code:

CSI Extractor (csi_extractor.py):
- Real ESP32 CSI parsing with I/Q to amplitude/phase conversion
- Real Atheros CSI Tool binary format parsing
- Real Intel 5300 CSI Tool format support
- Binary and text format auto-detection
- Proper hardware connection management

CSI Processor (csi_processor.py):
- Real Doppler shift calculation from phase history
- Phase rate of change to frequency conversion
- Proper temporal analysis using CSI history

Router Interface (router_interface.py):
- Real SSH connection using asyncssh
- Router type detection (OpenWRT, DD-WRT, Atheros CSI Tool)
- Multiple CSI collection methods (debugfs, procfs, CSI tool)
- Real binary CSI data parsing

Pose Service (pose_service.py):
- Real pose parsing from DensePose segmentation output
- Connected component analysis for person detection
- Keypoint extraction from body part segmentation
- Activity classification from keypoint geometry
- Bounding box calculation from detected regions

Removed random.uniform/random.randint/np.random in production code paths.
2026-01-14 18:10:12 +00:00
Claude 7c00482314 fix: Clean up Rust warnings and add Python vital signs detection
Rust changes:
- Fix unused variable warnings in wifi-densepose-nn (densepose.rs, inference.rs, tensor.rs, translator.rs)
- Remove unused imports in wifi-densepose-mat (breathing.rs, pipeline.rs, csi_receiver.rs, debris_model.rs, vital_signs_classifier.rs)
- All tests continue to pass

Python changes:
- Add vital_signs.py module with BreathingDetector and HeartbeatDetector classes
- Mirror Rust wifi-densepose-mat detection functionality
- Update v1 package version to 1.2.0
- Export new vital signs classes from core module
2026-01-14 17:42:37 +00:00
2428 changed files with 24644 additions and 1097359 deletions
-1
View File
@@ -1 +0,0 @@
{"intelligence":7,"timestamp":1774922079152}
-403
View File
@@ -1,403 +0,0 @@
# Claude Flow V3 - Complete Capabilities Reference
> Generated: 2026-02-28T16:04:10.839Z
> Full documentation: https://github.com/ruvnet/claude-flow
## 📋 Table of Contents
1. [Overview](#overview)
2. [Swarm Orchestration](#swarm-orchestration)
3. [Available Agents (60+)](#available-agents)
4. [CLI Commands (26 Commands, 140+ Subcommands)](#cli-commands)
5. [Hooks System (27 Hooks + 12 Workers)](#hooks-system)
6. [Memory & Intelligence (RuVector)](#memory--intelligence)
7. [Hive-Mind Consensus](#hive-mind-consensus)
8. [Performance Targets](#performance-targets)
9. [Integration Ecosystem](#integration-ecosystem)
---
## Overview
Claude Flow V3 is a domain-driven design architecture for multi-agent AI coordination with:
- **15-Agent Swarm Coordination** with hierarchical and mesh topologies
- **HNSW Vector Search** - 150x-12,500x faster pattern retrieval
- **SONA Neural Learning** - Self-optimizing with <0.05ms adaptation
- **Byzantine Fault Tolerance** - Queen-led consensus mechanisms
- **MCP Server Integration** - Model Context Protocol support
### Current Configuration
| Setting | Value |
|---------|-------|
| Topology | hierarchical-mesh |
| Max Agents | 15 |
| Memory Backend | hybrid |
| HNSW Indexing | Enabled |
| Neural Learning | Enabled |
| LearningBridge | Enabled (SONA + ReasoningBank) |
| Knowledge Graph | Enabled (PageRank + Communities) |
| Agent Scopes | Enabled (project/local/user) |
---
## Swarm Orchestration
### Topologies
| Topology | Description | Best For |
|----------|-------------|----------|
| `hierarchical` | Queen controls workers directly | Anti-drift, tight control |
| `mesh` | Fully connected peer network | Distributed tasks |
| `hierarchical-mesh` | V3 hybrid (recommended) | 10+ agents |
| `ring` | Circular communication | Sequential workflows |
| `star` | Central coordinator | Simple coordination |
| `adaptive` | Dynamic based on load | Variable workloads |
### Strategies
- `balanced` - Even distribution across agents
- `specialized` - Clear roles, no overlap (anti-drift)
- `adaptive` - Dynamic task routing
### Quick Commands
```bash
# Initialize swarm
npx @claude-flow/cli@latest swarm init --topology hierarchical --max-agents 8 --strategy specialized
# Check status
npx @claude-flow/cli@latest swarm status
# Monitor activity
npx @claude-flow/cli@latest swarm monitor
```
---
## Available Agents
### Core Development (5)
`coder`, `reviewer`, `tester`, `planner`, `researcher`
### V3 Specialized (4)
`security-architect`, `security-auditor`, `memory-specialist`, `performance-engineer`
### Swarm Coordination (5)
`hierarchical-coordinator`, `mesh-coordinator`, `adaptive-coordinator`, `collective-intelligence-coordinator`, `swarm-memory-manager`
### Consensus & Distributed (7)
`byzantine-coordinator`, `raft-manager`, `gossip-coordinator`, `consensus-builder`, `crdt-synchronizer`, `quorum-manager`, `security-manager`
### Performance & Optimization (5)
`perf-analyzer`, `performance-benchmarker`, `task-orchestrator`, `memory-coordinator`, `smart-agent`
### GitHub & Repository (9)
`github-modes`, `pr-manager`, `code-review-swarm`, `issue-tracker`, `release-manager`, `workflow-automation`, `project-board-sync`, `repo-architect`, `multi-repo-swarm`
### SPARC Methodology (6)
`sparc-coord`, `sparc-coder`, `specification`, `pseudocode`, `architecture`, `refinement`
### Specialized Development (8)
`backend-dev`, `mobile-dev`, `ml-developer`, `cicd-engineer`, `api-docs`, `system-architect`, `code-analyzer`, `base-template-generator`
### Testing & Validation (2)
`tdd-london-swarm`, `production-validator`
### Agent Routing by Task
| Task Type | Recommended Agents | Topology |
|-----------|-------------------|----------|
| Bug Fix | researcher, coder, tester | mesh |
| New Feature | coordinator, architect, coder, tester, reviewer | hierarchical |
| Refactoring | architect, coder, reviewer | mesh |
| Performance | researcher, perf-engineer, coder | hierarchical |
| Security | security-architect, auditor, reviewer | hierarchical |
| Docs | researcher, api-docs | mesh |
---
## CLI Commands
### Core Commands (12)
| Command | Subcommands | Description |
|---------|-------------|-------------|
| `init` | 4 | Project initialization |
| `agent` | 8 | Agent lifecycle management |
| `swarm` | 6 | Multi-agent coordination |
| `memory` | 11 | AgentDB with HNSW search |
| `mcp` | 9 | MCP server management |
| `task` | 6 | Task assignment |
| `session` | 7 | Session persistence |
| `config` | 7 | Configuration |
| `status` | 3 | System monitoring |
| `workflow` | 6 | Workflow templates |
| `hooks` | 17 | Self-learning hooks |
| `hive-mind` | 6 | Consensus coordination |
### Advanced Commands (14)
| Command | Subcommands | Description |
|---------|-------------|-------------|
| `daemon` | 5 | Background workers |
| `neural` | 5 | Pattern training |
| `security` | 6 | Security scanning |
| `performance` | 5 | Profiling & benchmarks |
| `providers` | 5 | AI provider config |
| `plugins` | 5 | Plugin management |
| `deployment` | 5 | Deploy management |
| `embeddings` | 4 | Vector embeddings |
| `claims` | 4 | Authorization |
| `migrate` | 5 | V2→V3 migration |
| `process` | 4 | Process management |
| `doctor` | 1 | Health diagnostics |
| `completions` | 4 | Shell completions |
### Example Commands
```bash
# Initialize
npx @claude-flow/cli@latest init --wizard
# Spawn agent
npx @claude-flow/cli@latest agent spawn -t coder --name my-coder
# Memory operations
npx @claude-flow/cli@latest memory store --key "pattern" --value "data" --namespace patterns
npx @claude-flow/cli@latest memory search --query "authentication"
# Diagnostics
npx @claude-flow/cli@latest doctor --fix
```
---
## Hooks System
### 27 Available Hooks
#### Core Hooks (6)
| Hook | Description |
|------|-------------|
| `pre-edit` | Context before file edits |
| `post-edit` | Record edit outcomes |
| `pre-command` | Risk assessment |
| `post-command` | Command metrics |
| `pre-task` | Task start + agent suggestions |
| `post-task` | Task completion learning |
#### Session Hooks (4)
| Hook | Description |
|------|-------------|
| `session-start` | Start/restore session |
| `session-end` | Persist state |
| `session-restore` | Restore previous |
| `notify` | Cross-agent notifications |
#### Intelligence Hooks (5)
| Hook | Description |
|------|-------------|
| `route` | Optimal agent routing |
| `explain` | Routing decisions |
| `pretrain` | Bootstrap intelligence |
| `build-agents` | Generate configs |
| `transfer` | Pattern transfer |
#### Coverage Hooks (3)
| Hook | Description |
|------|-------------|
| `coverage-route` | Coverage-based routing |
| `coverage-suggest` | Improvement suggestions |
| `coverage-gaps` | Gap analysis |
### 12 Background Workers
| Worker | Priority | Purpose |
|--------|----------|---------|
| `ultralearn` | normal | Deep knowledge |
| `optimize` | high | Performance |
| `consolidate` | low | Memory consolidation |
| `predict` | normal | Predictive preload |
| `audit` | critical | Security |
| `map` | normal | Codebase mapping |
| `preload` | low | Resource preload |
| `deepdive` | normal | Deep analysis |
| `document` | normal | Auto-docs |
| `refactor` | normal | Suggestions |
| `benchmark` | normal | Benchmarking |
| `testgaps` | normal | Coverage gaps |
---
## Memory & Intelligence
### RuVector Intelligence System
- **SONA**: Self-Optimizing Neural Architecture (<0.05ms)
- **MoE**: Mixture of Experts routing
- **HNSW**: 150x-12,500x faster search
- **EWC++**: Prevents catastrophic forgetting
- **Flash Attention**: 2.49x-7.47x speedup
- **Int8 Quantization**: 3.92x memory reduction
### 4-Step Intelligence Pipeline
1. **RETRIEVE** - HNSW pattern search
2. **JUDGE** - Success/failure verdicts
3. **DISTILL** - LoRA learning extraction
4. **CONSOLIDATE** - EWC++ preservation
### Self-Learning Memory (ADR-049)
| Component | Status | Description |
|-----------|--------|-------------|
| **LearningBridge** | ✅ Enabled | Connects insights to SONA/ReasoningBank neural pipeline |
| **MemoryGraph** | ✅ Enabled | PageRank knowledge graph + community detection |
| **AgentMemoryScope** | ✅ Enabled | 3-scope agent memory (project/local/user) |
**LearningBridge** - Insights trigger learning trajectories. Confidence evolves: +0.03 on access, -0.005/hour decay. Consolidation runs the JUDGE/DISTILL/CONSOLIDATE pipeline.
**MemoryGraph** - Builds a knowledge graph from entry references. PageRank identifies influential insights. Communities group related knowledge. Graph-aware ranking blends vector + structural scores.
**AgentMemoryScope** - Maps Claude Code 3-scope directories:
- `project`: `<gitRoot>/.claude/agent-memory/<agent>/`
- `local`: `<gitRoot>/.claude/agent-memory-local/<agent>/`
- `user`: `~/.claude/agent-memory/<agent>/`
High-confidence insights (>0.8) can transfer between agents.
### Memory Commands
```bash
# Store pattern
npx @claude-flow/cli@latest memory store --key "name" --value "data" --namespace patterns
# Semantic search
npx @claude-flow/cli@latest memory search --query "authentication"
# List entries
npx @claude-flow/cli@latest memory list --namespace patterns
# Initialize database
npx @claude-flow/cli@latest memory init --force
```
---
## Hive-Mind Consensus
### Queen Types
| Type | Role |
|------|------|
| Strategic Queen | Long-term planning |
| Tactical Queen | Execution coordination |
| Adaptive Queen | Dynamic optimization |
### Worker Types (8)
`researcher`, `coder`, `analyst`, `tester`, `architect`, `reviewer`, `optimizer`, `documenter`
### Consensus Mechanisms
| Mechanism | Fault Tolerance | Use Case |
|-----------|-----------------|----------|
| `byzantine` | f < n/3 faulty | Adversarial |
| `raft` | f < n/2 failed | Leader-based |
| `gossip` | Eventually consistent | Large scale |
| `crdt` | Conflict-free | Distributed |
| `quorum` | Configurable | Flexible |
### Hive-Mind Commands
```bash
# Initialize
npx @claude-flow/cli@latest hive-mind init --queen-type strategic
# Status
npx @claude-flow/cli@latest hive-mind status
# Spawn workers
npx @claude-flow/cli@latest hive-mind spawn --count 5 --type worker
# Consensus
npx @claude-flow/cli@latest hive-mind consensus --propose "task"
```
---
## Performance Targets
| Metric | Target | Status |
|--------|--------|--------|
| HNSW Search | 150x-12,500x faster | ✅ Implemented |
| Memory Reduction | 50-75% | ✅ Implemented (3.92x) |
| SONA Integration | Pattern learning | ✅ Implemented |
| Flash Attention | 2.49x-7.47x | 🔄 In Progress |
| MCP Response | <100ms | ✅ Achieved |
| CLI Startup | <500ms | ✅ Achieved |
| SONA Adaptation | <0.05ms | 🔄 In Progress |
| Graph Build (1k) | <200ms | ✅ 2.78ms (71.9x headroom) |
| PageRank (1k) | <100ms | ✅ 12.21ms (8.2x headroom) |
| Insight Recording | <5ms/each | ✅ 0.12ms (41x headroom) |
| Consolidation | <500ms | ✅ 0.26ms (1,955x headroom) |
| Knowledge Transfer | <100ms | ✅ 1.25ms (80x headroom) |
---
## Integration Ecosystem
### Integrated Packages
| Package | Version | Purpose |
|---------|---------|---------|
| agentic-flow | 3.0.0-alpha.1 | Core coordination + ReasoningBank + Router |
| agentdb | 3.0.0-alpha.10 | Vector database + 8 controllers |
| @ruvector/attention | 0.1.3 | Flash attention |
| @ruvector/sona | 0.1.5 | Neural learning |
### Optional Integrations
| Package | Command |
|---------|---------|
| ruv-swarm | `npx ruv-swarm mcp start` |
| flow-nexus | `npx flow-nexus@latest mcp start` |
| agentic-jujutsu | `npx agentic-jujutsu@latest` |
### MCP Server Setup
```bash
# Add Claude Flow MCP
claude mcp add claude-flow -- npx -y @claude-flow/cli@latest
# Optional servers
claude mcp add ruv-swarm -- npx -y ruv-swarm mcp start
claude mcp add flow-nexus -- npx -y flow-nexus@latest mcp start
```
---
## Quick Reference
### Essential Commands
```bash
# Setup
npx @claude-flow/cli@latest init --wizard
npx @claude-flow/cli@latest daemon start
npx @claude-flow/cli@latest doctor --fix
# Swarm
npx @claude-flow/cli@latest swarm init --topology hierarchical --max-agents 8
npx @claude-flow/cli@latest swarm status
# Agents
npx @claude-flow/cli@latest agent spawn -t coder
npx @claude-flow/cli@latest agent list
# Memory
npx @claude-flow/cli@latest memory search --query "patterns"
# Hooks
npx @claude-flow/cli@latest hooks pre-task --description "task"
npx @claude-flow/cli@latest hooks worker dispatch --trigger optimize
```
### File Structure
```
.claude-flow/
├── config.yaml # Runtime configuration
├── CAPABILITIES.md # This file
├── data/ # Memory storage
├── logs/ # Operation logs
├── sessions/ # Session state
├── hooks/ # Custom hooks
├── agents/ # Agent configs
└── workflows/ # Workflow templates
```
---
**Full Documentation**: https://github.com/ruvnet/claude-flow
**Issues**: https://github.com/ruvnet/claude-flow/issues
+1 -16
View File
@@ -1,5 +1,5 @@
# Claude Flow V3 Runtime Configuration
# Generated: 2026-02-28T16:04:10.837Z
# Generated: 2026-01-13T02:28:22.177Z
version: "3.0.0"
@@ -14,21 +14,6 @@ memory:
enableHNSW: true
persistPath: .claude-flow/data
cacheSize: 100
# ADR-049: Self-Learning Memory
learningBridge:
enabled: true
sonaMode: balanced
confidenceDecayRate: 0.005
accessBoostAmount: 0.03
consolidationThreshold: 10
memoryGraph:
enabled: true
pageRankDamping: 0.85
maxNodes: 5000
similarityThreshold: 0.8
agentScopes:
enabled: true
defaultScope: project
neural:
enabled: true
+32 -37
View File
@@ -1,55 +1,50 @@
{
"running": true,
"startedAt": "2026-05-24T22:26:25.030Z",
"startedAt": "2026-01-13T18:06:18.421Z",
"workers": {
"map": {
"runCount": 64,
"successCount": 64,
"runCount": 8,
"successCount": 8,
"failureCount": 0,
"averageDurationMs": 136.171875,
"lastRun": "2026-05-25T06:07:33.387Z",
"lastStartedAt": "2026-05-25T06:07:33.381Z",
"nextRun": "2026-05-25T06:26:25.410Z",
"averageDurationMs": 1.25,
"lastRun": "2026-01-13T18:21:18.435Z",
"nextRun": "2026-01-13T18:21:18.428Z",
"isRunning": false
},
"audit": {
"runCount": 72,
"successCount": 27,
"failureCount": 45,
"averageDurationMs": 26260.11111111111,
"lastRun": "2026-05-25T06:08:29.594Z",
"lastStartedAt": "2026-05-25T06:07:33.416Z",
"nextRun": "2026-05-25T06:18:32.928Z",
"runCount": 5,
"successCount": 0,
"failureCount": 5,
"averageDurationMs": 0,
"lastRun": "2026-01-13T18:13:18.424Z",
"nextRun": "2026-01-13T18:23:18.425Z",
"isRunning": false
},
"optimize": {
"runCount": 54,
"successCount": 9,
"failureCount": 45,
"averageDurationMs": 40303.377578766485,
"lastRun": "2026-05-25T05:59:05.330Z",
"lastStartedAt": "2026-05-25T05:54:05.318Z",
"nextRun": "2026-05-25T06:20:15.145Z",
"runCount": 4,
"successCount": 0,
"failureCount": 4,
"averageDurationMs": 0,
"lastRun": "2026-01-13T18:15:18.424Z",
"nextRun": "2026-01-13T18:30:18.424Z",
"isRunning": false
},
"consolidate": {
"runCount": 32,
"successCount": 32,
"runCount": 3,
"successCount": 3,
"failureCount": 0,
"averageDurationMs": 4.71875,
"lastRun": "2026-05-25T05:38:20.449Z",
"lastStartedAt": "2026-05-25T05:38:20.443Z",
"nextRun": "2026-05-25T06:32:25.248Z",
"averageDurationMs": 0.6666666666666666,
"lastRun": "2026-01-13T18:13:18.428Z",
"nextRun": "2026-01-13T18:42:18.422Z",
"isRunning": false
},
"testgaps": {
"runCount": 100,
"successCount": 63,
"failureCount": 37,
"averageDurationMs": 108604.0537328991,
"lastRun": "2026-05-25T06:11:52.529Z",
"lastStartedAt": "2026-05-25T06:07:33.390Z",
"nextRun": "2026-05-25T06:14:25.296Z",
"runCount": 3,
"successCount": 0,
"failureCount": 3,
"averageDurationMs": 0,
"lastRun": "2026-01-13T18:19:18.457Z",
"nextRun": "2026-01-13T18:39:18.457Z",
"isRunning": false
},
"predict": {
@@ -69,8 +64,8 @@
},
"config": {
"autoStart": false,
"logDir": "C:\\Users\\ruv\\Projects\\wifi-densepose\\.claude-flow\\logs",
"stateFile": "C:\\Users\\ruv\\Projects\\wifi-densepose\\.claude-flow\\daemon-state.json",
"logDir": "/home/user/wifi-densepose/.claude-flow/logs",
"stateFile": "/home/user/wifi-densepose/.claude-flow/daemon-state.json",
"maxConcurrent": 2,
"workerTimeoutMs": 300000,
"resourceThresholds": {
@@ -136,5 +131,5 @@
}
]
},
"savedAt": "2026-05-25T06:11:52.530Z"
"savedAt": "2026-01-13T18:21:18.435Z"
}
+1
View File
@@ -0,0 +1 @@
589
-119
View File
@@ -1,119 +0,0 @@
{
"id": "aether-arena-aa",
"name": "AetherArena (AA) — Official Spatial-Intelligence Benchmark",
"adr": "ADR-149",
"adrPath": "docs/adr/ADR-149-public-community-leaderboard-huggingface.md",
"status": "Accepted",
"initializedDate": "2026-05-30",
"targetDate": "2026-08-31",
"exitCriteria": "Benchmark INFRASTRUCTURE done, tested, CI-gated, deploy-ready: aa_score_runner.rs passes deterministic fixture test; CI harness-gate green on every PR; aether-arena repo scaffold committed (README four-part framing + aa-submission.toml schema + VERIFY.md); public smoke split committed; HF Space lifecycle skeleton deployed; signed Parquet ledger functional; RuView baseline PCK@20 ~2.5% entered; ADR-149 §7 acceptance test (five-step stranger test) passes. NOTE: ML SOTA (MM-Fi PCK@20 ~72%) is a separate long-running stretch goal blocked on ADR-079 camera-ground-truth — it is NOT an infra exit criterion.",
"baselineState": {
"adrStatus": "Accepted, committed 2026-05-30",
"scorerCode": "ruview_metrics.rs + ablation.rs + proof.rs exist in wifi-densepose-train; aa_score_runner.rs not yet created",
"aetherArenaRepo": "does not exist yet — needs user authorization to create ruvnet/aether-arena public repo",
"hfSpace": "does not exist yet — needs HF_TOKEN and user authorization to deploy ruvnet/aether-arena HF Space",
"smokeDataset": "not committed",
"resultsLedger": "not created",
"ruviewBaseline": "PCK@20 ~2.5% self-reported, not formally entered",
"ciGate": "not added to workflow"
},
"milestones": {
"m1": {
"name": "ADR-149 Accepted + committed",
"status": "DONE",
"completedDate": "2026-05-30",
"completionCriteria": "ADR-149 file committed to docs/adr/ with status Accepted",
"notes": "Done this session. File at docs/adr/ADR-149-public-community-leaderboard-huggingface.md"
},
"m2": {
"name": "Deterministic scorer runner bin (aa_score_runner.rs)",
"status": "NOT_STARTED",
"completionCriteria": "aa_score_runner.rs compiles, runs ruview_metrics on a committed fixture, emits RuViewTier + SHA-256 proof hash, mirrors existing *_proof_runner.rs pattern; cargo test passes",
"estimatedEffort": "3-5 days",
"owner": "wifi-densepose-train crate or new aa-scorer crate"
},
"m3": {
"name": "CI harness-gate: GitHub Actions workflow",
"status": "NOT_STARTED",
"completionCriteria": "A GitHub Actions workflow runs aa_score_runner on every PR as a build gate; PR fails if scorer fails determinism check; workflow committed and green",
"estimatedEffort": "2-3 days",
"dependency": "M2 must be done first"
},
"m4": {
"name": "aether-arena repo scaffold",
"status": "NOT_STARTED",
"completionCriteria": "ruvnet/aether-arena repo created with: README (four-part framing: Public leaderboard / Private eval split / Open scorer / Signed results); aa-submission.toml manifest schema; VERIFY.md (ADR-149 §7 stranger acceptance test); neutrality/governance section (§2.8); contribution guide",
"estimatedEffort": "3-5 days",
"blockers": ["Needs user authorization to create public ruvnet/aether-arena repo on GitHub"]
},
"m5": {
"name": "Public smoke split committed + private MM-Fi held-out split prep",
"status": "NOT_STARTED",
"completionCriteria": "Public smoke split committed to aether-arena repo (stranger can score locally); private MM-Fi held-out split prepared under non-public path with CC BY-NC 4.0 attribution; Wi-Pose explicitly excluded from v0",
"estimatedEffort": "5-7 days",
"riskNotes": "MM-Fi CC BY-NC 4.0: AA must remain non-commercial and carry MM-Fi attribution; raw frames stay in private split; only derived CSI features + scores may be exposed"
},
"m6": {
"name": "HF Space (Gradio) skeleton",
"status": "BLOCKED",
"completionCriteria": "HF Space deployed at ruvnet/aether-arena with submission lifecycle (submitted->validated->quarantined->smoke_scored->full_scored->published/rejected); sandboxed scorer container wired; basic leaderboard table rendered",
"estimatedEffort": "7-10 days",
"blockers": [
"Needs HF_TOKEN — check .env for HF_TOKEN or HUGGINGFACE_TOKEN",
"Needs user authorization to create/deploy ruvnet/aether-arena HF Space (outward-facing public deployment)"
]
},
"m7": {
"name": "Signed append-only Parquet results ledger",
"status": "NOT_STARTED",
"completionCriteria": "HF dataset ruvnet/aether-arena-results created; append-only Parquet ledger with signed rows; determinism_gate enforced; no row can be silently edited",
"estimatedEffort": "3-5 days",
"ledgerSchema": "submitter, model_ref, category, feature_set, tier, pck20, oks, mota, vitals_bpm_err, latency_p50, latency_p95, privacy_leakage, cross_room_deg, proof_sha256, scored_at, harness_version",
"dependency": "M6 must be scaffolded first"
},
"m8": {
"name": "RuView baseline entry + public launch",
"status": "NOT_STARTED",
"completionCriteria": "RuView wifi-densepose-pretrained baseline entered (honest PCK@20 ~2.5%); ADR-149 §7 five-step stranger acceptance test passes; v0 live with Presence + Pose + Edge-latency + Determinism categories active; Privacy and Cross-room shown as gated/coming-soon",
"estimatedEffort": "3-5 days",
"dependency": "M4+M5+M6+M7 complete",
"notes": "ML SOTA improvement (PCK@20 ~72%) is a SEPARATE stretch goal blocked on ADR-079 P7-P9 camera ground truth. NOT a blocker for infra launch."
}
},
"activeMilestone": "m2",
"completedMilestones": ["m1"],
"knownRisks": [
"HF_TOKEN not confirmed present in .env — check before M6 work begins",
"ruvnet/aether-arena public repo creation is outward-facing — needs explicit user authorization",
"MM-Fi CC BY-NC 4.0: AA must stay legally non-commercial and brand-distinct from commercial RuView product; or seek MM-Fi commercial grant before any paid tier",
"Wi-Pose has research-use-only terms (no redistribution grant) — excluded from v0; revisit only if terms are clarified with authors",
"HF Space free CPU tier may be too slow for Candle/tch inference pipeline — may need ZeroGPU or self-hosted scorer on cognitum-20260110 GCloud A100/L4",
"ADR-079 camera-ground-truth (PCK@20 SOTA) is P7-P9 pending — NOT an infra blocker; must not be conflated with AA infra completion",
"Neutrality/governance risk: RuView seeded the scorer — must be demonstrably scored through the same public pipeline as any other entrant (§2.8 controls)"
],
"driftSignals": {
"timeline": "GREEN — just initialized, no timeline pressure yet",
"scope": "GREEN — scope locked at four-part structure per ADR-149 §2 decision",
"approach": "GREEN — reuse pattern (existing ruview_metrics + proof.rs) confirmed in ADR-149",
"dependency": "YELLOW — HF_TOKEN and ruvnet/aether-arena repo authorization are external blockers with unknown ETA",
"priority": "GREEN — active feature branch feat/adr-136-146-streaming-engine in progress; AA infra can proceed in parallel on its own branch"
},
"stretchGoals": {
"sotaML": "MM-Fi PCK@20 SOTA ~72% — separate ML effort blocked on ADR-079 P7-P9 camera-ground-truth data collection; NOT an infra exit criterion",
"privacyAxis": "ADR-145 §10 membership-inference attacker — activate Privacy leaderboard axis once attacker is implemented and published",
"crossRoom": "Multi-room held-out split — activate Cross-room generalization axis",
"multiOrgSteering": "Invite co-maintainers from other projects once >=N external entries land"
},
"sessionHistory": [
{
"date": "2026-05-30",
"type": "initialization",
"accomplished": [
"ADR-149 Accepted and committed to docs/adr/",
"Horizon record initialized in .claude-flow/horizons/aether-arena-aa.json",
"Memory stored in horizons namespace under key horizon-aether-arena-aa",
"Session check-in record stored in horizon-sessions namespace"
]
}
]
}
+3 -3
View File
@@ -1,11 +1,11 @@
{
"timestamp": "2026-05-25T06:07:33.385Z",
"projectRoot": "C:\\Users\\ruv\\Projects\\wifi-densepose",
"timestamp": "2026-01-13T18:21:18.434Z",
"projectRoot": "/home/user/wifi-densepose",
"structure": {
"hasPackageJson": false,
"hasTsConfig": false,
"hasClaudeConfig": true,
"hasClaudeFlow": true
},
"scannedAt": 1779689253386
"scannedAt": 1768328478434
}
+1 -1
View File
@@ -1,5 +1,5 @@
{
"timestamp": "2026-05-25T05:38:20.448Z",
"timestamp": "2026-01-13T18:13:18.428Z",
"patternsConsolidated": 0,
"memoryCleaned": 0,
"duplicatesRemoved": 0
-17
View File
@@ -1,17 +0,0 @@
{
"initialized": "2026-02-28T16:04:10.843Z",
"routing": {
"accuracy": 0,
"decisions": 0
},
"patterns": {
"shortTerm": 0,
"longTerm": 0,
"quality": 0
},
"sessions": {
"total": 0,
"current": null
},
"_note": "Intelligence grows as you use Claude Flow"
}
-17
View File
@@ -1,17 +0,0 @@
{
"timestamp": "2026-05-25T05:59:05.405Z",
"mode": "local",
"memoryUsage": {
"rss": 9891840,
"heapTotal": 35598336,
"heapUsed": 26516560,
"external": 3952418,
"arrayBuffers": 55689
},
"uptime": 27163.5846658,
"optimizations": {
"cacheHitRate": 0.78,
"avgResponseTime": 45
},
"note": "Install Claude Code CLI for AI-powered optimization suggestions"
}
-84
View File
@@ -1,84 +0,0 @@
{
"timestamp": "2026-05-25T06:08:29.589Z",
"mode": "headless",
"workerType": "audit",
"model": "haiku",
"durationMs": 56168,
"executionId": "audit_1779689253421_dfflmb",
"success": true,
"findings": {
"vulnerabilities": [
{
"severity": "high",
"file": ".claude/helpers/github-safe.js",
"line": 50,
"description": "Command injection vulnerability in execSync call. User-controlled arguments in `newArgs` are joined without shell escaping. An attacker can inject shell metacharacters (e.g., `; rm -rf /`) via the body content or through command/subcommand parameters. The temp file approach is safe, but the command construction `gh ${command} ${subcommand} ${newArgs.join(' ')}` allows shell injection.",
"example": "gh issue comment 123 'test`whoami`' would execute whoami"
},
{
"severity": "high",
"file": "scripts/csi-spectrogram.js",
"line": 45,
"description": "Sensitive credential exposure via command-line arguments. The `--seed-token` parameter is passed as a CLI argument, which is visible in process listings (ps aux output). This violates secure credential handling practices. Tokens should be read from environment variables or secure config files, not command-line args.",
"example": "node scripts/csi-spectrogram.js --seed-token secret_abc_123 exposes token in process list"
},
{
"severity": "medium",
"file": "scripts/apnea-detector.js",
"line": 71,
"description": "Unsafe buffer reading without comprehensive length validation. The code checks `buf.length` at 32 bytes (line 70) but then reads at fixed offsets (lines 72-76) without validating that each read stays within bounds. If a malformed packet is received, `readInt8/readUInt16LE/readUInt32LE` may read unintended data or zeros.",
"example": "A 33-byte buffer would pass the check but reading UInt32LE at offset 8 would go out of bounds"
},
{
"severity": "medium",
"file": "scripts/benchmark-rf-scan.js",
"line": 110,
"description": "Potential out-of-bounds buffer access in parseCSIFrame. While the bounds check at line 107 is present, the `nSubcarriers` value from the packet is used to calculate required buffer size without validation of the value itself. A maliciously crafted packet with extremely large nSubcarriers could cause memory issues.",
"example": "Packet with nSubcarriers=999999 would request excessive buffer allocation"
},
{
"severity": "medium",
"file": "scripts/csi-spectrogram.js",
"line": 39,
"description": "Unsafe URL construction with untrusted `seed-url` parameter. The `--seed-url` argument is used directly for HTTPS requests without validation. This could allow SSRF (Server-Side Request Forgery) or DNS rebinding attacks if an attacker controls the seed URL.",
"example": "node scripts/csi-spectrogram.js --seed-url http://internal.local:9000 could access internal services"
},
{
"severity": "low",
"file": ".claude/helpers/statusline.js",
"line": 140,
"description": "Shell command injection risk in execSync calls. Commands like `ps aux 2>/dev/null | grep -c agentic-flow` use grep patterns that could be vulnerable if any variables are interpolated (though currently hardcoded). The `execSync` with shell=true is generally risky.",
"example": "If any pattern becomes user-controlled: `grep -c ${pattern}` could inject shell metacharacters"
},
{
"severity": "low",
"file": ".claude/helpers/memory.js",
"line": 10,
"description": "Unvalidated JSON parsing. The code parses JSON from MEMORY_FILE without try-catch in the loadMemory function (catches error but doesn't validate structure). Malformed JSON or corrupted memory file could cause issues.",
"example": "Memory file with circular JSON structure could cause issues when stringifying"
},
{
"severity": "low",
"file": "scripts/device-fingerprint.js",
"line": 72,
"description": "Hardcoded device fingerprints and network configuration. While not a traditional 'hardcoded secret', the KNOWN_DEVICES array contains identifiable SSIDs and MAC addresses that could be used to correlate network infrastructure. This data should be externalized or sanitized.",
"example": "SSID 'ruv.net' and 'Cohen-Guest' could identify specific installations"
}
],
"riskScore": 42,
"recommendations": [
"**CRITICAL**: Replace `execSync` command construction in github-safe.js with proper shell escaping using `child_process.execFile()` instead of `execSync()`, or use the `shell: false` option with array arguments to avoid shell parsing entirely.",
"**CRITICAL**: Move `--seed-token` from CLI arguments to environment variable `SEED_TOKEN` in csi-spectrogram.js. Update documentation to instruct users: `export SEED_TOKEN=...` instead of passing via CLI.",
"**HIGH**: Add comprehensive buffer bounds validation in all UDP packet parsing functions (apnea-detector.js, benchmark-rf-scan.js, etc.). Validate both the buffer length AND the parsed header values before using them in calculations.",
"**HIGH**: Validate and sanitize the `--seed-url` parameter in csi-spectrogram.js. Whitelist allowed domains or restrict to localhost/internal IPs only. Add URL scheme validation (https only).",
"**MEDIUM**: Replace hardcoded device fingerprints (KNOWN_DEVICES) with externalized configuration or environment variables. Document that this data contains identifiable network information.",
"**MEDIUM**: Add input validation to `parseArgs()` results in all scripts. Validate numeric ranges, file paths, and enum values before use.",
"**LOW**: Wrap JSON.parse() calls in try-catch blocks throughout (memory.js, session.js) with explicit error handling and recovery.",
"**LOW**: Audit all uses of `require()` with dynamic paths. Ensure paths are always derived from fixed `__dirname` and not user-controlled.",
"**LOW**: Remove or sandbox the ability to pass arbitrary URLs via CLI. Consider using a configuration file (YAML/JSON) for endpoint URLs instead.",
"**INFO**: Add a pre-commit hook to detect hardcoded credentials using tools like `detect-secrets` or `truffleHog`."
]
},
"rawOutputPreview": "# Security Audit Report — wifi-densepose\n\n```json\n{\n \"vulnerabilities\": [\n {\n \"severity\": \"high\",\n \"file\": \".claude/helpers/github-safe.js\",\n \"line\": 50,\n \"description\": \"Command injection vulnerability in execSync call. User-controlled arguments in `newArgs` are joined without shell escaping. An attacker can inject shell metacharacters (e.g., `; rm -rf /`) via the body content or through command/subcommand parameters. The temp file approach is safe, but the command construction `gh ${command} ${subcommand} ${newArgs.join(' ')}` allows shell injection.\",\n \"example\": \"gh issue comment 123 'test`whoami`' would execute whoami\"\n },\n {\n \"severity\": \"high\",\n \"file\": \"scripts/csi-spectrogram.js\",\n \"line\": 45,\n \"description\": \"Sensitive credential exposure via command-line arguments. The `--seed-token` parameter is passed as a CLI argument, which is visible in process listings (ps aux output). This violates secure credential handling practices. Tokens should be read from environment variables or secure config files, not command-line args.\",\n \"example\": \"node scripts/csi-spectrogram.js --seed-token secret_abc_123 exposes token in process list\"\n },\n {\n \"severity\": \"medium\",\n \"file\": \"scripts/apnea-detector.js\",\n \"line\": 71,\n \"description\": \"Unsafe buffer reading without comprehensive length validation. The code checks `buf.length` at 32 bytes (line 70) but then reads at fixed offsets (lines 72-76) without validating that each read stays within bounds. If a malformed packet is received, `readInt8/readUInt16LE/readUInt32LE` may read unintended data or zeros.\",\n \"example\": \"A 33-byte buffer would pass the check but reading UInt32LE at offset 8 would go out of bounds\"\n },\n {\n \"severity\": \"medium\",\n \"file\": \"scripts/benchmark-rf-scan.js\",\n \"line\": 110,\n \"description\": \"Potential out-of-bounds buffer access in parseCSIFrame. While the bounds check at line 107 is pres",
"rawOutputLength": 7077
}
-18
View File
@@ -1,18 +0,0 @@
{
"timestamp": "2026-02-28T16:04:10.842Z",
"processes": {
"agentic_flow": 0,
"mcp_server": 0,
"estimated_agents": 0
},
"swarm": {
"active": false,
"agent_count": 0,
"coordination_active": false
},
"integration": {
"agentic_flow_active": false,
"mcp_active": false
},
"_initialized": true
}
-106
View File
@@ -1,106 +0,0 @@
{
"timestamp": "2026-05-25T06:11:52.519Z",
"mode": "headless",
"workerType": "testgaps",
"model": "sonnet",
"durationMs": 259124,
"executionId": "testgaps_1779689253395_srltd5",
"success": true,
"findings": {
"sections": [
{
"title": "Test Coverage Gap Analysis — wifi-densepose",
"content": "\n",
"level": 2
},
{
"title": "Coverage Summary by Crate",
"content": "\n| Crate | Tests Found | Status | Priority |\n|-------|-------------|--------|----------|\n| `wifi-densepose-core` | 26 inline | Good | Low |\n| `wifi-densepose-signal` | ~60 (validation only) | Moderate | **High** |\n| `wifi-densepose-nn` | **0** | Critical | **P1** |\n| `wifi-densepose-train` | ~60 (config/dataset) | Moderate | High |\n| `wifi-densepose-mat` | 1 integration test | Critical | **P1** |\n| `wifi-densepose-ruvector` | **0** | Critical | **P1** |\n| `wifi-densepose-sensing-server` | 4 integration tests | Moderate | High |\n| `wifi-densepose-wasm` | 3 compliance tests | Low | Low |\n\n---\n\n",
"level": 3
},
{
"title": "Tier 1: Critical Gaps",
"content": "\n",
"level": 2
},
{
"title": "1. `wifi-densepose-nn` — Zero test coverage",
"content": "\nEvery public API is untested. Place these at `v2/crates/wifi-densepose-nn/tests/inference_tests.rs`:\n\n```rust\n// v2/crates/wifi-densepose-nn/tests/inference_tests.rs\n\n#[cfg(test)]\nmod tensor_tests {\n use wifi_densepose_nn::tensor::Tensor;\n\n #[test]\n fn tensor_shape_mismatch_returns_error() {\n // data has 6 elements but shape claims 3×3=9\n let result = Tensor::new(vec![1.0f32; 6], &[3, 3]);\n assert!(result.is_err(), \"shape mismatch must be rejected\");\n }\n\n #[test]\n fn tensor_empty_data_returns_error() {\n let result = Tensor::new(vec![], &[0]);\n assert!(result.is_err());\n }\n\n #[test]\n fn tensor_nan_values_are_detected() {\n let t = Tensor::new(vec![f32::NAN, 1.0, 2.0], &[3]).unwrap();\n assert!(t.has_nan(), \"NaN in data must be detectable\");\n }\n\n #[test]\n fn tensor_inf_values_are_detected() {\n let t = Tensor::new(vec![f32::INFINITY, 1.0], &[2]).unwrap();\n assert!(t.has_inf());\n }\n}\n\n#[cfg(test)]\nmod modality_translator_tests {\n use wifi_densepose_nn::translator::ModalityTranslator;\n\n #[test]\n fn translator_rejects_wrong_subcarrier_count() {\n // standard expects 56 subcarriers; feed 57\n let csi = vec![0.0f32; 57 * 3]; // 57 subcarriers × 3 antennas\n let translator = ModalityTranslator::default();\n let result = translator.translate(&csi, 57, 3);\n assert!(result.is_err());\n }\n\n #[test]\n fn translator_handles_all_zeros() {\n let csi = vec![0.0f32; 56 * 3];\n let translator = ModalityTranslator::default();\n let result = translator.translate(&csi, 56, 3);\n // zero input should produce some output without panic\n assert!(result.is_ok());\n }\n}\n\n#[cfg(test)]\nmod inference_engine_tests {\n use wifi_densepose_nn::inference::InferenceEngine;\n\n #[test]\n fn load_nonexistent_model_returns_error() {\n let result = InferenceEngine::from_path(\"/nonexistent/model.onnx\");\n assert!(result.is_err());\n }\n\n #[test]\n fn load_corrupted_bytes_returns_error() {\n let tmp = tempfile::NamedTempFile::new().unwrap();\n std::fs::write(tmp.path(), b\"not a valid onnx file\").unwrap();\n let result = InferenceEngine::from_path(tmp.path());\n assert!(result.is_err());\n }\n\n #[test]\n fn batch_size_zero_returns_error() {\n // can't run inference on an empty batch\n // requires a valid model; skip if no model file in test fixtures\n // use #[ignore] or a feature flag for CI\n }\n}\n```\n\n---\n\n",
"level": 3
},
{
"title": "2. `wifi-densepose-mat` — Disaster response safety gaps",
"content": "\nPlace at `v2/crates/wifi-densepose-mat/tests/`:\n\n```rust\n// v2/crates/wifi-densepose-mat/tests/detection_edge_cases.rs\n\n#[cfg(test)]\nmod breathing_rate_edge_cases {\n use wifi_densepose_mat::detection::breathing::BreathingDetector;\n\n #[test]\n fn zero_bpm_is_classified_critical() {\n let detector = BreathingDetector::default();\n // flat-line signal — no breathing detected\n let signal = vec![0.0f32; 1000];\n let result = detector.classify(&signal).unwrap();\n assert_eq!(result.triage_category, TriageCategory::Immediate);\n }\n\n #[test]\n fn agonal_breathing_rate_triggers_immediate() {\n // < 6 BPM is agonal; simulate 3 BPM signal\n let detector = BreathingDetector::default();\n let signal = generate_breathing_signal(3.0, 1000, 100.0); // 3 BPM, 1000 samples @ 100 Hz\n let result = detector.classify(&signal).unwrap();\n assert_eq!(result.triage_category, TriageCategory::Immediate);\n }\n\n #[test]\n fn normal_breathing_is_classified_minor() {\n let detector = BreathingDetector::default();\n let signal = generate_breathing_signal(15.0, 1000, 100.0); // 15 BPM\n let result = detector.classify(&signal).unwrap();\n assert_eq!(result.triage_category, TriageCategory::Minor);\n }\n\n #[test]\n fn all_nan_signal_returns_error_not_panic() {\n let detector = BreathingDetector::default();\n let signal = vec![f32::NAN; 1000];\n let result = detector.classify(&signal);\n assert!(result.is_err(), \"NaN input must be caught, not panic\");\n }\n\n fn generate_breathing_signal(bpm: f32, samples: usize, sample_rate: f32) -> Vec<f32> {\n let freq = bpm / 60.0;\n (0..samples)\n .map(|i| (2.0 * std::f32::consts::PI * freq * i as f32 / sample_rate).sin())\n .collect()\n }\n}\n\n#[cfg(test)]\nmod alert_deduplication {\n use wifi_densepose_mat::alerting::{AlertDispatcher, Alert, TriageCategory};\n use std::time::Duration;\n\n #[test]\n fn duplicate_alerts_within_window_are_suppressed() {\n let mut dispatcher = AlertDispatcher::new();\n let alert = Alert::new(\"survivor-1\", TriageCategory::Immediate);\n dispatcher.dispatch(alert.clone());\n dispatcher.dispatch(alert.clone()); // same survivor, same category\n assert_eq!(dispatcher.queued_count(), 1, \"duplicate must be deduplicated\");\n }\n\n #[test]\n fn escalation_from_minor_to_immediate_is_forwarded() {\n let mut dispatcher = AlertDispatcher::new();\n dispatcher.dispatch(Alert::new(\"survivor-1\", TriageCategory::Minor));\n dispatcher.dispatch(Alert::new(\"survivor-1\", TriageCategory::Immediate));\n // escalation is not a duplicate — must pass through\n assert!(dispatcher.last_alert_for(\"survivor-1\").map(|a| a.category) == Some(TriageCategory::Immediate));\n }\n}\n\n#[cfg(test)]\nmod kalman_tracker_edge_cases {\n use wifi_densepose_mat::tracking::KalmanTracker;\n\n #[test]\n fn position_jump_does_not_corrupt_state() {\n let mut tracker = KalmanTracker::new();\n tracker.update([1.0, 1.0, 0.5]); // initial position\n tracker.update([50.0, 50.0, 0.5]); // physically impossible jump\n let pos = tracker.estimated_position();\n // should not panic; should clamp or flag anomaly\n assert!(pos.iter().all(|v| v.is_finite()));\n }\n\n #[test]\n fn lost_track_resumes_on_re_detection() {\n let mut tracker = KalmanTracker::new();\n tracker.update([1.0, 1.0, 0.5]);\n // simulate 10 missed frames\n for _ in 0..10 { tracker.predict(); }\n assert_eq!(tracker.state(), TrackState::Lost);\n tracker.update([1.1, 1.1, 0.5]); // re-detected nearby\n assert_eq!(tracker.state(), TrackState::Confirmed);\n }\n}\n```\n\n---\n\n",
"level": 3
},
{
"title": "3. `wifi-densepose-ruvector` — Zero coverage on all 5 integration modules",
"content": "\n```rust\n// v2/crates/wifi-densepose-ruvector/tests/viewpoint_tests.rs\n\n#[cfg(test)]\nmod attention_tests {\n use wifi_densepose_ruvector::viewpoint::attention::CrossViewpointAttention;\n\n #[test]\n fn attention_weights_sum_to_one() {\n let attn = CrossViewpointAttention::new(3); // 3 viewpoints\n let features = vec![[1.0f32; 64], [2.0f32; 64], [3.0f32; 64]];\n let weights = attn.compute_weights(&features);\n let sum: f32 = weights.iter().sum();\n assert!((sum - 1.0).abs() < 1e-5, \"attention must be a probability distribution\");\n }\n\n #[test]\n fn single_viewpoint_gets_full_weight() {\n let attn = CrossViewpointAttention::new(1);\n let features = vec![[1.0f32; 64]];\n let weights = attn.compute_weights(&features);\n assert!((weights[0] - 1.0).abs() < 1e-6);\n }\n\n #[test]\n fn zero_feature_vectors_do_not_produce_nan() {\n let attn = CrossViewpointAttention::new(2);\n let features = vec![[0.0f32; 64], [0.0f32; 64]];\n let weights = attn.compute_weights(&features);\n assert!(weights.iter().all(|w| w.is_finite()));\n }\n}\n\n#[cfg(test)]\nmod sketch_tests {\n use wifi_densepose_ruvector::sketch::WireSketch;\n\n #[test]\n fn round_trip_serialization() {\n let sketch = WireSketch::from_keypoints(&[[0.5f32, 0.5], [0.3, 0.7]]);\n let bytes = sketch.to_bytes();\n let restored = WireSketch::from_bytes(&bytes).unwrap();\n assert_eq!(sketch, restored);\n }\n\n #[test]\n fn deserialize_truncated_bytes_returns_error() {\n let sketch = WireSketch::from_keypoints(&[[0.5f32, 0.5]]);\n let mut bytes = sketch.to_bytes();\n bytes.truncate(bytes.len() / 2); // truncate halfway\n assert!(WireSketch::from_bytes(&bytes).is_err());\n }\n\n #[test]\n fn empty_keypoint_list_is_handled() {\n let sketch = WireSketch::from_keypoints(&[]);\n assert_eq!(sketch.keypoint_count(), 0);\n }\n}\n```\n\n---\n\n",
"level": 3
},
{
"title": "Tier 2: Signal Processing Gaps",
"content": "\n",
"level": 2
},
{
"title": "4. `wifi-densepose-signal` — RuvSense module untested",
"content": "\n```rust\n// v2/crates/wifi-densepose-signal/tests/ruvsense_tests.rs\n\n#[cfg(test)]\nmod coherence_gate_tests {\n use wifi_densepose_signal::ruvsense::coherence_gate::{CoherenceGate, GateDecision};\n\n #[test]\n fn high_coherence_signal_is_accepted() {\n let gate = CoherenceGate::new(0.7); // threshold = 0.7\n let decision = gate.evaluate(0.95);\n assert_eq!(decision, GateDecision::Accept);\n }\n\n #[test]\n fn low_coherence_signal_is_rejected() {\n let gate = CoherenceGate::new(0.7);\n let decision = gate.evaluate(0.3);\n assert_eq!(decision, GateDecision::Reject);\n }\n\n #[test]\n fn borderline_coherence_triggers_recalibrate() {\n let gate = CoherenceGate::new(0.7);\n let decision = gate.evaluate(0.68); // just below threshold\n assert_eq!(decision, GateDecision::Recalibrate);\n }\n}\n\n#[cfg(test)]\nmod phase_align_tests {\n use wifi_densepose_signal::ruvsense::phase_align::PhaseAligner;\n\n #[test]\n fn phase_at_plus_pi_does_not_wrap_incorrectly() {\n let aligner = PhaseAligner::new();\n let phases = vec![std::f32::consts::PI - 0.001, std::f32::consts::PI + 0.001];\n let aligned = aligner.align(&phases);\n // jump across ±π boundary must be handled continuously\n let diff = (aligned[1] - aligned[0]).abs();\n assert!(diff < 0.01, \"phase jump at ±π must be < 0.01 rad after alignment\");\n }\n\n #[test]\n fn single_phase_value_aligns_to_itself() {\n let aligner = PhaseAligner::new();\n let phases = vec![1.5f32];\n let aligned = aligner.align(&phases);\n assert_eq!(aligned.len(), 1);\n assert!((aligned[0] - 1.5).abs() < 1e-6);\n }\n\n #[test]\n fn empty_phase_array_returns_empty() {\n let aligner = PhaseAligner::new();\n let aligned = aligner.align(&[]);\n assert!(aligned.is_empty());\n }\n}\n\n#[cfg(test)]\nmod adversarial_detection_tests {\n use wifi_densepose_signal::ruvsense::adversarial::AdversarialDetector;\n\n #[test]\n fn physically_impossible_amplitude_is_flagged() {\n let detector = AdversarialDetector::new();\n // WiFi amplitude cannot exceed hardware saturation level\n let frame = vec![1e9f32; 56]; // absurdly large\n assert!(detector.is_suspicious(&frame));\n }\n\n #[test]\n fn normal_amplitude_range_passes() {\n let detector = AdversarialDetector::new();\n let frame = vec![0.5f32; 56]; // typical normalized value\n assert!(!detector.is_suspicious(&frame));\n }\n\n #[test]\n fn multi_link_inconsistency_is_detected() {\n // link A reports body moving right; link B reports no motion\n // physically inconsistent — flag as adversarial\n let detector = AdversarialDetector::new();\n let result = detector.check_multi_link_consistency(\n &[1.0, 2.0, 3.0], // link A\n &[0.0, 0.0, 0.0], // link B (no motion)\n );\n assert!(result.is_inconsistent());\n }\n}\n```\n\n---\n\n",
"level": 3
},
{
"title": "Tier 2: Training Pipeline Gaps",
"content": "\n",
"level": 2
},
{
"title": "5. `wifi-densepose-train` — Geometry encoder and rapid adaptation untested",
"content": "\n```rust\n// v2/crates/wifi-densepose-train/tests/test_geometry.rs\n\n#[cfg(test)]\nmod film_layer_tests {\n use wifi_densepose_train::geometry::FilmLayer;\n\n #[test]\n fn film_layer_output_shape_matches_input() {\n let film = FilmLayer::new(64, 32); // 64-dim features, 32-dim condition\n let features = vec![0.5f32; 64];\n let condition = vec![1.0f32; 32];\n let output = film.forward(&features, &condition).unwrap();\n assert_eq!(output.len(), 64, \"FiLM output must match feature dimensionality\");\n }\n\n #[test]\n fn film_layer_zero_condition_acts_as_identity() {\n let film = FilmLayer::new(64, 32);\n let features = vec![1.0f32; 64];\n let zero_condition = vec![0.0f32; 32];\n let output = film.forward(&features, &zero_condition).unwrap();\n // scale=1, shift=0 → identity; output ≈ input\n for (o, f) in output.iter().zip(features.iter()) {\n assert!((o - f).abs() < 0.1, \"zero condition should approximate identity\");\n }\n }\n}\n\n// v2/crates/wifi-densepose-train/tests/test_rapid_adapt.rs\n\n#[cfg(test)]\nmod rapid_adaptation_tests {\n use wifi_densepose_train::rapid_adapt::RapidAdapter;\n\n #[test]\n fn adapter_updates_on_single_sample() {\n let mut adapter = RapidAdapter::new(5); // 5 adaptation steps\n let csi_sample = vec![0.1f32; 56 * 3];\n let pose_label = vec![0.5f32; 17 * 2]; // 17 keypoints × (x, y)\n let result = adapter.adapt_step(&csi_sample, &pose_label);\n assert!(result.is_ok());\n }\n\n #[test]\n fn adapter_with_zero_steps_is_no_op() {\n let adapter = RapidAdapter::new(0);\n // 0 adaptation steps → weights unchanged\n let initial_weights = adapter.clone_weights();\n let _ = adapter.adapt_step(&vec![0.1f32; 168], &vec![0.5f32; 34]);\n assert_eq!(adapter.clone_weights(), initial_weights);\n }\n}\n```\n\n---\n\n",
"level": 3
},
{
"title": "Tier 3: Server Integration Gaps",
"content": "\n",
"level": 2
},
{
"title": "6. `wifi-densepose-sensing-server` — Auth and semantic analyzers",
"content": "\n```rust\n// v2/crates/wifi-densepose-sensing-server/tests/auth_tests.rs\n\n#[cfg(test)]\nmod bearer_auth_tests {\n use wifi_densepose_sensing_server::auth::{BearerValidator, TokenError};\n\n #[test]\n fn missing_authorization_header_returns_unauthorized() {\n let validator = BearerValidator::new(\"secret-token\");\n let result = validator.validate(None);\n assert!(matches!(result, Err(TokenError::Missing)));\n }\n\n #[test]\n fn wrong_token_is_rejected() {\n let validator = BearerValidator::new(\"correct-token\");\n let result = validator.validate(Some(\"Bearer wrong-token\"));\n assert!(matches!(result, Err(TokenError::Invalid)));\n }\n\n #[test]\n fn malformed_header_without_bearer_prefix_is_rejected() {\n let validator = BearerValidator::new(\"token\");\n let result = validator.validate(Some(\"token\")); // missing \"Bearer \" prefix\n assert!(matches!(result, Err(TokenError::Malformed)));\n }\n\n #[test]\n fn correct_token_is_accepted() {\n let validator = BearerValidator::new(\"correct-token\");\n let result = validator.validate(Some(\"Bearer correct-token\"));\n assert!(result.is_ok());\n }\n}\n\n// v2/crates/wifi-densepose-sensing-server/tests/semantic_tests.rs\n\n#[cfg(test)]\nmod fall_detection_tests {\n use wifi_densepose_sensing_server::semantic::fall_detector::FallDetector;\n\n #[test]\n fn no_motion_does_not_trigger_fall() {\n let mut detector = FallDetector::new();\n for _ in 0..30 { // 30 frames of stillness\n detector.update_pose(stationary_pose());\n }\n assert!(!detector.fall_detected());\n }\n\n #[test]\n fn rapid_downward_velocity_triggers_fall() {\n let mut detector = FallDetector::new();\n // simulate person going from standing (y=1.7m) to prone (y=0.3m) in 3 frames\n for (frame, y) in [(0, 1.7f32), (1, 1.0), (2, 0.3)] {\n detector.update_pose(pose_at_height(y));\n }\n assert!(detector.fall_detected());\n }\n\n #[test]\n fn sitting_down_slowly_does_not_trigger_fall() {\n let mut detector = FallDetector::new();\n // gradual height decrease over 30 frames is sitting, not falling\n for i in 0..30 {\n let y = 1.7f32 - (i as f32 * 0.04); // ~1.2m drop over 30 frames\n detector.update_pose(pose_at_height(y));\n }\n assert!(!detector.fall_detected());\n }\n}\n```\n\n---\n\n",
"level": 3
},
{
"title": "Cross-Cutting Gap Summary",
"content": "| Gap Category | Severity | Affects | Recommended Action |\n|---|---|---|---|\n| `wifi-densepose-nn` has 0 tests | **Critical** | Inference pipeline | Add `tests/inference_tests.rs` per skeleton above |\n| `wifi-densepose-ruvector` has 0 tests | **Critical** | Viewpoint fusion, sketches | Add `tests/viewpoint_tests.rs` |\n| MAT disaster response missing edge cases | **Critical** | 0 BPM, agonal breathing, dedup | Add `tests/detection_edge_cases.rs` |\n| Signal RuvSense 28 modules untested | High | Core sensing logic | Add `tests/ruvsense_tests.rs` |\n| NN error paths (bad model files, OOM) | High | Production reliability | Add error path tests to nn |\n| Train geometry + rapid adapt = 0 tests | High | Domain adaptation | Add `tests/test_geometry.rs` |\n| Server auth token validation | High | Security boundary | Add `tests/auth_tests.rs` |\n| NaN/Inf propagation in f32 pipelines | High | All numeric crates | Add boundary tests per module |\n| Concurrent state under Arc<Mutex> | Medium | sensing-server, mat | Add contention tests |\n\nThe highest-ROI starting point is `wifi-densepose-nn` and `wifi-densepose-mat` — the nn crate has zero tests on the core inference pipeline, and mat covers life-safety scenarios where classification errors have real consequences.",
"level": 2
}
],
"codeBlocks": [
{
"language": "rust",
"code": "// v2/crates/wifi-densepose-nn/tests/inference_tests.rs\n\n#[cfg(test)]\nmod tensor_tests {\n use wifi_densepose_nn::tensor::Tensor;\n\n #[test]\n fn tensor_shape_mismatch_returns_error() {\n // data has 6 elements but shape claims 3×3=9\n let result = Tensor::new(vec![1.0f32; 6], &[3, 3]);\n assert!(result.is_err(), \"shape mismatch must be rejected\");\n }\n\n #[test]\n fn tensor_empty_data_returns_error() {\n let result = Tensor::new(vec![], &[0]);\n assert!(result.is_err());\n }\n\n #[test]\n fn tensor_nan_values_are_detected() {\n let t = Tensor::new(vec![f32::NAN, 1.0, 2.0], &[3]).unwrap();\n assert!(t.has_nan(), \"NaN in data must be detectable\");\n }\n\n #[test]\n fn tensor_inf_values_are_detected() {\n let t = Tensor::new(vec![f32::INFINITY, 1.0], &[2]).unwrap();\n assert!(t.has_inf());\n }\n}\n\n#[cfg(test)]\nmod modality_translator_tests {\n use wifi_densepose_nn::translator::ModalityTranslator;\n\n #[test]\n fn translator_rejects_wrong_subcarrier_count() {\n // standard expects 56 subcarriers; feed 57\n let csi = vec![0.0f32; 57 * 3]; // 57 subcarriers × 3 antennas\n let translator = ModalityTranslator::default();\n let result = translator.translate(&csi, 57, 3);\n assert!(result.is_err());\n }\n\n #[test]\n fn translator_handles_all_zeros() {\n let csi = vec![0.0f32; 56 * 3];\n let translator = ModalityTranslator::default();\n let result = translator.translate(&csi, 56, 3);\n // zero input should produce some output without panic\n assert!(result.is_ok());\n }\n}\n\n#[cfg(test)]\nmod inference_engine_tests {\n use wifi_densepose_nn::inference::InferenceEngine;\n\n #[test]\n fn load_nonexistent_model_returns_error() {\n let result = InferenceEngine::from_path(\"/nonexistent/model.onnx\");\n assert!(result.is_err());\n }\n\n #[test]\n fn load_corrupted_bytes_returns_error() {\n let tmp = tempfile::NamedTempFile::new().unwrap();\n std::fs::write(tmp.path(), b\"not a valid onnx file\").unwrap();\n let result = InferenceEngine::from_path(tmp.path());\n assert!(result.is_err());\n }\n\n #[test]\n fn batch_size_zero_returns_error() {\n // can't run inference on an empty batch\n // requires a valid model; skip if no model file in test fixtures\n // use #[ignore] or a feature flag for CI\n }\n}"
},
{
"language": "rust",
"code": "// v2/crates/wifi-densepose-mat/tests/detection_edge_cases.rs\n\n#[cfg(test)]\nmod breathing_rate_edge_cases {\n use wifi_densepose_mat::detection::breathing::BreathingDetector;\n\n #[test]\n fn zero_bpm_is_classified_critical() {\n let detector = BreathingDetector::default();\n // flat-line signal — no breathing detected\n let signal = vec![0.0f32; 1000];\n let result = detector.classify(&signal).unwrap();\n assert_eq!(result.triage_category, TriageCategory::Immediate);\n }\n\n #[test]\n fn agonal_breathing_rate_triggers_immediate() {\n // < 6 BPM is agonal; simulate 3 BPM signal\n let detector = BreathingDetector::default();\n let signal = generate_breathing_signal(3.0, 1000, 100.0); // 3 BPM, 1000 samples @ 100 Hz\n let result = detector.classify(&signal).unwrap();\n assert_eq!(result.triage_category, TriageCategory::Immediate);\n }\n\n #[test]\n fn normal_breathing_is_classified_minor() {\n let detector = BreathingDetector::default();\n let signal = generate_breathing_signal(15.0, 1000, 100.0); // 15 BPM\n let result = detector.classify(&signal).unwrap();\n assert_eq!(result.triage_category, TriageCategory::Minor);\n }\n\n #[test]\n fn all_nan_signal_returns_error_not_panic() {\n let detector = BreathingDetector::default();\n let signal = vec![f32::NAN; 1000];\n let result = detector.classify(&signal);\n assert!(result.is_err(), \"NaN input must be caught, not panic\");\n }\n\n fn generate_breathing_signal(bpm: f32, samples: usize, sample_rate: f32) -> Vec<f32> {\n let freq = bpm / 60.0;\n (0..samples)\n .map(|i| (2.0 * std::f32::consts::PI * freq * i as f32 / sample_rate).sin())\n .collect()\n }\n}\n\n#[cfg(test)]\nmod alert_deduplication {\n use wifi_densepose_mat::alerting::{AlertDispatcher, Alert, TriageCategory};\n use std::time::Duration;\n\n #[test]\n fn duplicate_alerts_within_window_are_suppressed() {\n let mut dispatcher = AlertDispatcher::new();\n let alert = Alert::new(\"survivor-1\", TriageCategory::Immediate);\n dispatcher.dispatch(alert.clone());\n dispatcher.dispatch(alert.clone()); // same survivor, same category\n assert_eq!(dispatcher.queued_count(), 1, \"duplicate must be deduplicated\");\n }\n\n #[test]\n fn escalation_from_minor_to_immediate_is_forwarded() {\n let mut dispatcher = AlertDispatcher::new();\n dispatcher.dispatch(Alert::new(\"survivor-1\", TriageCategory::Minor));\n dispatcher.dispatch(Alert::new(\"survivor-1\", TriageCategory::Immediate));\n // escalation is not a duplicate — must pass through\n assert!(dispatcher.last_alert_for(\"survivor-1\").map(|a| a.category) == Some(TriageCategory::Immediate));\n }\n}\n\n#[cfg(test)]\nmod kalman_tracker_edge_cases {\n use wifi_densepose_mat::tracking::KalmanTracker;\n\n #[test]\n fn position_jump_does_not_corrupt_state() {\n let mut tracker = KalmanTracker::new();\n tracker.update([1.0, 1.0, 0.5]); // initial position\n tracker.update([50.0, 50.0, 0.5]); // physically impossible jump\n let pos = tracker.estimated_position();\n // should not panic; should clamp or flag anomaly\n assert!(pos.iter().all(|v| v.is_finite()));\n }\n\n #[test]\n fn lost_track_resumes_on_re_detection() {\n let mut tracker = KalmanTracker::new();\n tracker.update([1.0, 1.0, 0.5]);\n // simulate 10 missed frames\n for _ in 0..10 { tracker.predict(); }\n assert_eq!(tracker.state(), TrackState::Lost);\n tracker.update([1.1, 1.1, 0.5]); // re-detected nearby\n assert_eq!(tracker.state(), TrackState::Confirmed);\n }\n}"
},
{
"language": "rust",
"code": "// v2/crates/wifi-densepose-ruvector/tests/viewpoint_tests.rs\n\n#[cfg(test)]\nmod attention_tests {\n use wifi_densepose_ruvector::viewpoint::attention::CrossViewpointAttention;\n\n #[test]\n fn attention_weights_sum_to_one() {\n let attn = CrossViewpointAttention::new(3); // 3 viewpoints\n let features = vec![[1.0f32; 64], [2.0f32; 64], [3.0f32; 64]];\n let weights = attn.compute_weights(&features);\n let sum: f32 = weights.iter().sum();\n assert!((sum - 1.0).abs() < 1e-5, \"attention must be a probability distribution\");\n }\n\n #[test]\n fn single_viewpoint_gets_full_weight() {\n let attn = CrossViewpointAttention::new(1);\n let features = vec![[1.0f32; 64]];\n let weights = attn.compute_weights(&features);\n assert!((weights[0] - 1.0).abs() < 1e-6);\n }\n\n #[test]\n fn zero_feature_vectors_do_not_produce_nan() {\n let attn = CrossViewpointAttention::new(2);\n let features = vec![[0.0f32; 64], [0.0f32; 64]];\n let weights = attn.compute_weights(&features);\n assert!(weights.iter().all(|w| w.is_finite()));\n }\n}\n\n#[cfg(test)]\nmod sketch_tests {\n use wifi_densepose_ruvector::sketch::WireSketch;\n\n #[test]\n fn round_trip_serialization() {\n let sketch = WireSketch::from_keypoints(&[[0.5f32, 0.5], [0.3, 0.7]]);\n let bytes = sketch.to_bytes();\n let restored = WireSketch::from_bytes(&bytes).unwrap();\n assert_eq!(sketch, restored);\n }\n\n #[test]\n fn deserialize_truncated_bytes_returns_error() {\n let sketch = WireSketch::from_keypoints(&[[0.5f32, 0.5]]);\n let mut bytes = sketch.to_bytes();\n bytes.truncate(bytes.len() / 2); // truncate halfway\n assert!(WireSketch::from_bytes(&bytes).is_err());\n }\n\n #[test]\n fn empty_keypoint_list_is_handled() {\n let sketch = WireSketch::from_keypoints(&[]);\n assert_eq!(sketch.keypoint_count(), 0);\n }\n}"
},
{
"language": "rust",
"code": "// v2/crates/wifi-densepose-signal/tests/ruvsense_tests.rs\n\n#[cfg(test)]\nmod coherence_gate_tests {\n use wifi_densepose_signal::ruvsense::coherence_gate::{CoherenceGate, GateDecision};\n\n #[test]\n fn high_coherence_signal_is_accepted() {\n let gate = CoherenceGate::new(0.7); // threshold = 0.7\n let decision = gate.evaluate(0.95);\n assert_eq!(decision, GateDecision::Accept);\n }\n\n #[test]\n fn low_coherence_signal_is_rejected() {\n let gate = CoherenceGate::new(0.7);\n let decision = gate.evaluate(0.3);\n assert_eq!(decision, GateDecision::Reject);\n }\n\n #[test]\n fn borderline_coherence_triggers_recalibrate() {\n let gate = CoherenceGate::new(0.7);\n let decision = gate.evaluate(0.68); // just below threshold\n assert_eq!(decision, GateDecision::Recalibrate);\n }\n}\n\n#[cfg(test)]\nmod phase_align_tests {\n use wifi_densepose_signal::ruvsense::phase_align::PhaseAligner;\n\n #[test]\n fn phase_at_plus_pi_does_not_wrap_incorrectly() {\n let aligner = PhaseAligner::new();\n let phases = vec![std::f32::consts::PI - 0.001, std::f32::consts::PI + 0.001];\n let aligned = aligner.align(&phases);\n // jump across ±π boundary must be handled continuously\n let diff = (aligned[1] - aligned[0]).abs();\n assert!(diff < 0.01, \"phase jump at ±π must be < 0.01 rad after alignment\");\n }\n\n #[test]\n fn single_phase_value_aligns_to_itself() {\n let aligner = PhaseAligner::new();\n let phases = vec![1.5f32];\n let aligned = aligner.align(&phases);\n assert_eq!(aligned.len(), 1);\n assert!((aligned[0] - 1.5).abs() < 1e-6);\n }\n\n #[test]\n fn empty_phase_array_returns_empty() {\n let aligner = PhaseAligner::new();\n let aligned = aligner.align(&[]);\n assert!(aligned.is_empty());\n }\n}\n\n#[cfg(test)]\nmod adversarial_detection_tests {\n use wifi_densepose_signal::ruvsense::adversarial::AdversarialDetector;\n\n #[test]\n fn physically_impossible_amplitude_is_flagged() {\n let detector = AdversarialDetector::new();\n // WiFi amplitude cannot exceed hardware saturation level\n let frame = vec![1e9f32; 56]; // absurdly large\n assert!(detector.is_suspicious(&frame));\n }\n\n #[test]\n fn normal_amplitude_range_passes() {\n let detector = AdversarialDetector::new();\n let frame = vec![0.5f32; 56]; // typical normalized value\n assert!(!detector.is_suspicious(&frame));\n }\n\n #[test]\n fn multi_link_inconsistency_is_detected() {\n // link A reports body moving right; link B reports no motion\n // physically inconsistent — flag as adversarial\n let detector = AdversarialDetector::new();\n let result = detector.check_multi_link_consistency(\n &[1.0, 2.0, 3.0], // link A\n &[0.0, 0.0, 0.0], // link B (no motion)\n );\n assert!(result.is_inconsistent());\n }\n}"
},
{
"language": "rust",
"code": "// v2/crates/wifi-densepose-train/tests/test_geometry.rs\n\n#[cfg(test)]\nmod film_layer_tests {\n use wifi_densepose_train::geometry::FilmLayer;\n\n #[test]\n fn film_layer_output_shape_matches_input() {\n let film = FilmLayer::new(64, 32); // 64-dim features, 32-dim condition\n let features = vec![0.5f32; 64];\n let condition = vec![1.0f32; 32];\n let output = film.forward(&features, &condition).unwrap();\n assert_eq!(output.len(), 64, \"FiLM output must match feature dimensionality\");\n }\n\n #[test]\n fn film_layer_zero_condition_acts_as_identity() {\n let film = FilmLayer::new(64, 32);\n let features = vec![1.0f32; 64];\n let zero_condition = vec![0.0f32; 32];\n let output = film.forward(&features, &zero_condition).unwrap();\n // scale=1, shift=0 → identity; output ≈ input\n for (o, f) in output.iter().zip(features.iter()) {\n assert!((o - f).abs() < 0.1, \"zero condition should approximate identity\");\n }\n }\n}\n\n// v2/crates/wifi-densepose-train/tests/test_rapid_adapt.rs\n\n#[cfg(test)]\nmod rapid_adaptation_tests {\n use wifi_densepose_train::rapid_adapt::RapidAdapter;\n\n #[test]\n fn adapter_updates_on_single_sample() {\n let mut adapter = RapidAdapter::new(5); // 5 adaptation steps\n let csi_sample = vec![0.1f32; 56 * 3];\n let pose_label = vec![0.5f32; 17 * 2]; // 17 keypoints × (x, y)\n let result = adapter.adapt_step(&csi_sample, &pose_label);\n assert!(result.is_ok());\n }\n\n #[test]\n fn adapter_with_zero_steps_is_no_op() {\n let adapter = RapidAdapter::new(0);\n // 0 adaptation steps → weights unchanged\n let initial_weights = adapter.clone_weights();\n let _ = adapter.adapt_step(&vec![0.1f32; 168], &vec![0.5f32; 34]);\n assert_eq!(adapter.clone_weights(), initial_weights);\n }\n}"
},
{
"language": "rust",
"code": "// v2/crates/wifi-densepose-sensing-server/tests/auth_tests.rs\n\n#[cfg(test)]\nmod bearer_auth_tests {\n use wifi_densepose_sensing_server::auth::{BearerValidator, TokenError};\n\n #[test]\n fn missing_authorization_header_returns_unauthorized() {\n let validator = BearerValidator::new(\"secret-token\");\n let result = validator.validate(None);\n assert!(matches!(result, Err(TokenError::Missing)));\n }\n\n #[test]\n fn wrong_token_is_rejected() {\n let validator = BearerValidator::new(\"correct-token\");\n let result = validator.validate(Some(\"Bearer wrong-token\"));\n assert!(matches!(result, Err(TokenError::Invalid)));\n }\n\n #[test]\n fn malformed_header_without_bearer_prefix_is_rejected() {\n let validator = BearerValidator::new(\"token\");\n let result = validator.validate(Some(\"token\")); // missing \"Bearer \" prefix\n assert!(matches!(result, Err(TokenError::Malformed)));\n }\n\n #[test]\n fn correct_token_is_accepted() {\n let validator = BearerValidator::new(\"correct-token\");\n let result = validator.validate(Some(\"Bearer correct-token\"));\n assert!(result.is_ok());\n }\n}\n\n// v2/crates/wifi-densepose-sensing-server/tests/semantic_tests.rs\n\n#[cfg(test)]\nmod fall_detection_tests {\n use wifi_densepose_sensing_server::semantic::fall_detector::FallDetector;\n\n #[test]\n fn no_motion_does_not_trigger_fall() {\n let mut detector = FallDetector::new();\n for _ in 0..30 { // 30 frames of stillness\n detector.update_pose(stationary_pose());\n }\n assert!(!detector.fall_detected());\n }\n\n #[test]\n fn rapid_downward_velocity_triggers_fall() {\n let mut detector = FallDetector::new();\n // simulate person going from standing (y=1.7m) to prone (y=0.3m) in 3 frames\n for (frame, y) in [(0, 1.7f32), (1, 1.0), (2, 0.3)] {\n detector.update_pose(pose_at_height(y));\n }\n assert!(detector.fall_detected());\n }\n\n #[test]\n fn sitting_down_slowly_does_not_trigger_fall() {\n let mut detector = FallDetector::new();\n // gradual height decrease over 30 frames is sitting, not falling\n for i in 0..30 {\n let y = 1.7f32 - (i as f32 * 0.04); // ~1.2m drop over 30 frames\n detector.update_pose(pose_at_height(y));\n }\n assert!(!detector.fall_detected());\n }\n}"
}
]
},
"rawOutputPreview": "The exploration is complete. Here's the full coverage analysis with test skeletons for each critical gap.\n\n---\n\n## Test Coverage Gap Analysis — wifi-densepose\n\n### Coverage Summary by Crate\n\n| Crate | Tests Found | Status | Priority |\n|-------|-------------|--------|----------|\n| `wifi-densepose-core` | 26 inline | Good | Low |\n| `wifi-densepose-signal` | ~60 (validation only) | Moderate | **High** |\n| `wifi-densepose-nn` | **0** | Critical | **P1** |\n| `wifi-densepose-train` | ~60 (config/dataset) | Moderate | High |\n| `wifi-densepose-mat` | 1 integration test | Critical | **P1** |\n| `wifi-densepose-ruvector` | **0** | Critical | **P1** |\n| `wifi-densepose-sensing-server` | 4 integration tests | Moderate | High |\n| `wifi-densepose-wasm` | 3 compliance tests | Low | Low |\n\n---\n\n## Tier 1: Critical Gaps\n\n### 1. `wifi-densepose-nn` — Zero test coverage\n\nEvery public API is untested. Place these at `v2/crates/wifi-densepose-nn/tests/inference_tests.rs`:\n\n```rust\n// v2/crates/wifi-densepose-nn/tests/inference_tests.rs\n\n#[cfg(test)]\nmod tensor_tests {\n use wifi_densepose_nn::tensor::Tensor;\n\n #[test]\n fn tensor_shape_mismatch_returns_error() {\n // data has 6 elements but shape claims 3×3=9\n let result = Tensor::new(vec![1.0f32; 6], &[3, 3]);\n assert!(result.is_err(), \"shape mismatch must be rejected\");\n }\n\n #[test]\n fn tensor_empty_data_returns_error() {\n let result = Tensor::new(vec![], &[0]);\n assert!(result.is_err());\n }\n\n #[test]\n fn tensor_nan_values_are_detected() {\n let t = Tensor::new(vec![f32::NAN, 1.0, 2.0], &[3]).unwrap();\n assert!(t.has_nan(), \"NaN in data must be detectable\");\n }\n\n #[test]\n fn tensor_inf_values_are_detected() {\n let t = Tensor::new(vec![f32::INFINITY, 1.0], &[2]).unwrap();\n assert!(t.has_inf());\n }\n}\n\n#[cfg(test)]\nmod modality_translator_tests {\n use wifi_densepose_nn::translator::ModalityTranslator;\n\n #[test]\n fn translator_rejects",
"rawOutputLength": 18269
}
-26
View File
@@ -1,26 +0,0 @@
{
"version": "3.0.0",
"initialized": "2026-02-28T16:04:10.841Z",
"domains": {
"completed": 0,
"total": 5,
"status": "INITIALIZING"
},
"ddd": {
"progress": 0,
"modules": 0,
"totalFiles": 0,
"totalLines": 0
},
"swarm": {
"activeAgents": 0,
"maxAgents": 15,
"topology": "hierarchical-mesh"
},
"learning": {
"status": "READY",
"patternsLearned": 0,
"sessionsCompleted": 0
},
"_note": "Metrics will update as you use Claude Flow. Run: npx @claude-flow/cli@latest daemon start"
}
-8
View File
@@ -1,8 +0,0 @@
{
"initialized": "2026-02-28T16:04:10.843Z",
"status": "PENDING",
"cvesFixed": 0,
"totalCves": 3,
"lastScan": null,
"_note": "Run: npx @claude-flow/cli@latest security scan"
}
-15
View File
@@ -1,15 +0,0 @@
{
"name": "ruview",
"description": "RuView Marketplace: Claude Code + Codex plugins for WiFi sensing — configuration, applications, model training, and onboarding, from practical to advanced",
"owner": {
"name": "ruvnet",
"url": "https://github.com/ruvnet/RuView"
},
"plugins": [
{
"name": "ruview",
"source": "./plugins/ruview",
"description": "End-to-end RuView toolkit: getting started, ESP32 hardware setup, configuration, sensing applications (presence / vitals / pose / sleep / MAT), camera-free + camera-supervised model training, advanced multistatic sensing, CLI / API / WASM, mmWave radar, and witness verification"
}
]
}
@@ -6,7 +6,9 @@ type: "analysis"
version: "1.0.0"
created: "2025-07-25"
author: "Claude Code"
metadata:
description: "Advanced code quality analysis agent for comprehensive code reviews and improvements"
specialization: "Code quality, best practices, refactoring suggestions, technical debt"
complexity: "complex"
autonomous: true
+2 -2
View File
@@ -1,5 +1,5 @@
---
name: analyst
name: code-analyzer
description: "Advanced code quality analysis agent for comprehensive code reviews and improvements"
type: code-analyzer
color: indigo
@@ -10,7 +10,7 @@ hooks:
post: |
npx claude-flow@alpha hooks post-task --task-id "analysis-${timestamp}" --analyze-performance true
metadata:
specialization: "Code quality assessment and security analysis"
description: Advanced code quality analysis agent for comprehensive code reviews and improvements
capabilities:
- Code quality assessment and metrics
- Performance bottleneck detection
@@ -1,179 +0,0 @@
---
name: "code-analyzer"
description: "Advanced code quality analysis agent for comprehensive code reviews and improvements"
color: "purple"
type: "analysis"
version: "1.0.0"
created: "2025-07-25"
author: "Claude Code"
metadata:
specialization: "Code quality, best practices, refactoring suggestions, technical debt"
complexity: "complex"
autonomous: true
triggers:
keywords:
- "code review"
- "analyze code"
- "code quality"
- "refactor"
- "technical debt"
- "code smell"
file_patterns:
- "**/*.js"
- "**/*.ts"
- "**/*.py"
- "**/*.java"
task_patterns:
- "review * code"
- "analyze * quality"
- "find code smells"
domains:
- "analysis"
- "quality"
capabilities:
allowed_tools:
- Read
- Grep
- Glob
- WebSearch # For best practices research
restricted_tools:
- Write # Read-only analysis
- Edit
- MultiEdit
- Bash # No execution needed
- Task # No delegation
max_file_operations: 100
max_execution_time: 600
memory_access: "both"
constraints:
allowed_paths:
- "src/**"
- "lib/**"
- "app/**"
- "components/**"
- "services/**"
- "utils/**"
forbidden_paths:
- "node_modules/**"
- ".git/**"
- "dist/**"
- "build/**"
- "coverage/**"
max_file_size: 1048576 # 1MB
allowed_file_types:
- ".js"
- ".ts"
- ".jsx"
- ".tsx"
- ".py"
- ".java"
- ".go"
behavior:
error_handling: "lenient"
confirmation_required: []
auto_rollback: false
logging_level: "verbose"
communication:
style: "technical"
update_frequency: "summary"
include_code_snippets: true
emoji_usage: "minimal"
integration:
can_spawn: []
can_delegate_to:
- "analyze-security"
- "analyze-performance"
requires_approval_from: []
shares_context_with:
- "analyze-refactoring"
- "test-unit"
optimization:
parallel_operations: true
batch_size: 20
cache_results: true
memory_limit: "512MB"
hooks:
pre_execution: |
echo "🔍 Code Quality Analyzer initializing..."
echo "📁 Scanning project structure..."
# Count files to analyze
find . -name "*.js" -o -name "*.ts" -o -name "*.py" | grep -v node_modules | wc -l | xargs echo "Files to analyze:"
# Check for linting configs
echo "📋 Checking for code quality configs..."
ls -la .eslintrc* .prettierrc* .pylintrc tslint.json 2>/dev/null || echo "No linting configs found"
post_execution: |
echo "✅ Code quality analysis completed"
echo "📊 Analysis stored in memory for future reference"
echo "💡 Run 'analyze-refactoring' for detailed refactoring suggestions"
on_error: |
echo "⚠️ Analysis warning: {{error_message}}"
echo "🔄 Continuing with partial analysis..."
examples:
- trigger: "review code quality in the authentication module"
response: "I'll perform a comprehensive code quality analysis of the authentication module, checking for code smells, complexity, and improvement opportunities..."
- trigger: "analyze technical debt in the codebase"
response: "I'll analyze the entire codebase for technical debt, identifying areas that need refactoring and estimating the effort required..."
---
# Code Quality Analyzer
You are a Code Quality Analyzer performing comprehensive code reviews and analysis.
## Key responsibilities:
1. Identify code smells and anti-patterns
2. Evaluate code complexity and maintainability
3. Check adherence to coding standards
4. Suggest refactoring opportunities
5. Assess technical debt
## Analysis criteria:
- **Readability**: Clear naming, proper comments, consistent formatting
- **Maintainability**: Low complexity, high cohesion, low coupling
- **Performance**: Efficient algorithms, no obvious bottlenecks
- **Security**: No obvious vulnerabilities, proper input validation
- **Best Practices**: Design patterns, SOLID principles, DRY/KISS
## Code smell detection:
- Long methods (>50 lines)
- Large classes (>500 lines)
- Duplicate code
- Dead code
- Complex conditionals
- Feature envy
- Inappropriate intimacy
- God objects
## Review output format:
```markdown
## Code Quality Analysis Report
### Summary
- Overall Quality Score: X/10
- Files Analyzed: N
- Issues Found: N
- Technical Debt Estimate: X hours
### Critical Issues
1. [Issue description]
- File: path/to/file.js:line
- Severity: High
- Suggestion: [Improvement]
### Code Smells
- [Smell type]: [Description]
### Refactoring Opportunities
- [Opportunity]: [Benefit]
### Positive Findings
- [Good practice observed]
```
@@ -1,155 +0,0 @@
---
name: "system-architect"
description: "Expert agent for system architecture design, patterns, and high-level technical decisions"
type: "architecture"
color: "purple"
version: "1.0.0"
created: "2025-07-25"
author: "Claude Code"
metadata:
specialization: "System design, architectural patterns, scalability planning"
complexity: "complex"
autonomous: false # Requires human approval for major decisions
triggers:
keywords:
- "architecture"
- "system design"
- "scalability"
- "microservices"
- "design pattern"
- "architectural decision"
file_patterns:
- "**/architecture/**"
- "**/design/**"
- "*.adr.md" # Architecture Decision Records
- "*.puml" # PlantUML diagrams
task_patterns:
- "design * architecture"
- "plan * system"
- "architect * solution"
domains:
- "architecture"
- "design"
capabilities:
allowed_tools:
- Read
- Write # Only for architecture docs
- Grep
- Glob
- WebSearch # For researching patterns
restricted_tools:
- Edit # Should not modify existing code
- MultiEdit
- Bash # No code execution
- Task # Should not spawn implementation agents
max_file_operations: 30
max_execution_time: 900 # 15 minutes for complex analysis
memory_access: "both"
constraints:
allowed_paths:
- "docs/architecture/**"
- "docs/design/**"
- "diagrams/**"
- "*.md"
- "README.md"
forbidden_paths:
- "src/**" # Read-only access to source
- "node_modules/**"
- ".git/**"
max_file_size: 5242880 # 5MB for diagrams
allowed_file_types:
- ".md"
- ".puml"
- ".svg"
- ".png"
- ".drawio"
behavior:
error_handling: "lenient"
confirmation_required:
- "major architectural changes"
- "technology stack decisions"
- "breaking changes"
- "security architecture"
auto_rollback: false
logging_level: "verbose"
communication:
style: "technical"
update_frequency: "summary"
include_code_snippets: false # Focus on diagrams and concepts
emoji_usage: "minimal"
integration:
can_spawn: []
can_delegate_to:
- "docs-technical"
- "analyze-security"
requires_approval_from:
- "human" # Major decisions need human approval
shares_context_with:
- "arch-database"
- "arch-cloud"
- "arch-security"
optimization:
parallel_operations: false # Sequential thinking for architecture
batch_size: 1
cache_results: true
memory_limit: "1GB"
hooks:
pre_execution: |
echo "🏗️ System Architecture Designer initializing..."
echo "📊 Analyzing existing architecture..."
echo "Current project structure:"
find . -type f -name "*.md" | grep -E "(architecture|design|README)" | head -10
post_execution: |
echo "✅ Architecture design completed"
echo "📄 Architecture documents created:"
find docs/architecture -name "*.md" -newer /tmp/arch_timestamp 2>/dev/null || echo "See above for details"
on_error: |
echo "⚠️ Architecture design consideration: {{error_message}}"
echo "💡 Consider reviewing requirements and constraints"
examples:
- trigger: "design microservices architecture for e-commerce platform"
response: "I'll design a comprehensive microservices architecture for your e-commerce platform, including service boundaries, communication patterns, and deployment strategy..."
- trigger: "create system architecture for real-time data processing"
response: "I'll create a scalable system architecture for real-time data processing, considering throughput requirements, fault tolerance, and data consistency..."
---
# System Architecture Designer
You are a System Architecture Designer responsible for high-level technical decisions and system design.
## Key responsibilities:
1. Design scalable, maintainable system architectures
2. Document architectural decisions with clear rationale
3. Create system diagrams and component interactions
4. Evaluate technology choices and trade-offs
5. Define architectural patterns and principles
## Best practices:
- Consider non-functional requirements (performance, security, scalability)
- Document ADRs (Architecture Decision Records) for major decisions
- Use standard diagramming notations (C4, UML)
- Think about future extensibility
- Consider operational aspects (deployment, monitoring)
## Deliverables:
1. Architecture diagrams (C4 model preferred)
2. Component interaction diagrams
3. Data flow diagrams
4. Architecture Decision Records
5. Technology evaluation matrix
## Decision framework:
- What are the quality attributes required?
- What are the constraints and assumptions?
- What are the trade-offs of each option?
- How does this align with business goals?
- What are the risks and mitigation strategies?
-182
View File
@@ -1,182 +0,0 @@
# Browser Agent Configuration
# AI-powered web browser automation using agent-browser
#
# Capabilities:
# - Web navigation and interaction
# - AI-optimized snapshots with element refs
# - Form filling and submission
# - Screenshot capture
# - Network interception
# - Multi-session coordination
name: browser-agent
description: Web automation specialist using agent-browser with AI-optimized snapshots
version: 1.0.0
# Routing configuration
routing:
complexity: medium
model: sonnet # Good at visual reasoning and DOM interpretation
priority: normal
keywords:
- browser
- web
- scrape
- screenshot
- navigate
- login
- form
- click
- automate
# Agent capabilities
capabilities:
- web-navigation
- form-interaction
- screenshot-capture
- data-extraction
- network-interception
- session-management
- multi-tab-coordination
# Available tools (MCP tools with browser/ prefix)
tools:
navigation:
- browser/open
- browser/back
- browser/forward
- browser/reload
- browser/close
snapshot:
- browser/snapshot
- browser/screenshot
- browser/pdf
interaction:
- browser/click
- browser/fill
- browser/type
- browser/press
- browser/hover
- browser/select
- browser/check
- browser/uncheck
- browser/scroll
- browser/upload
info:
- browser/get-text
- browser/get-html
- browser/get-value
- browser/get-attr
- browser/get-title
- browser/get-url
- browser/get-count
state:
- browser/is-visible
- browser/is-enabled
- browser/is-checked
wait:
- browser/wait
eval:
- browser/eval
storage:
- browser/cookies-get
- browser/cookies-set
- browser/cookies-clear
- browser/localstorage-get
- browser/localstorage-set
network:
- browser/network-route
- browser/network-unroute
- browser/network-requests
tabs:
- browser/tab-list
- browser/tab-new
- browser/tab-switch
- browser/tab-close
- browser/session-list
settings:
- browser/set-viewport
- browser/set-device
- browser/set-geolocation
- browser/set-offline
- browser/set-media
debug:
- browser/trace-start
- browser/trace-stop
- browser/console
- browser/errors
- browser/highlight
- browser/state-save
- browser/state-load
find:
- browser/find-role
- browser/find-text
- browser/find-label
- browser/find-testid
# Memory configuration
memory:
namespace: browser-sessions
persist: true
patterns:
- login-flows
- form-submissions
- scraping-patterns
- navigation-sequences
# Swarm integration
swarm:
roles:
- navigator # Handles authentication and navigation
- scraper # Extracts data using snapshots
- validator # Verifies extracted data
- tester # Runs automated tests
- monitor # Watches for errors and network issues
topology: hierarchical # Coordinator manages browser agents
max_sessions: 5
# Hooks integration
hooks:
pre_task:
- route # Get optimal routing
- memory_search # Check for similar patterns
post_task:
- memory_store # Save successful patterns
- post_edit # Train on outcomes
# Default configuration
defaults:
timeout: 30000
headless: true
viewport:
width: 1280
height: 720
# Example workflows
workflows:
login:
description: Authenticate to a website
steps:
- open: "{url}/login"
- snapshot: { interactive: true }
- fill: { target: "@e1", value: "{username}" }
- fill: { target: "@e2", value: "{password}" }
- click: "@e3"
- wait: { url: "**/dashboard" }
- state-save: "auth-state.json"
scrape_list:
description: Extract data from a list page
steps:
- open: "{url}"
- snapshot: { interactive: true, compact: true }
- eval: "Array.from(document.querySelectorAll('{selector}')).map(el => el.textContent)"
form_submit:
description: Fill and submit a form
steps:
- open: "{url}"
- snapshot: { interactive: true }
- fill_fields: "{fields}"
- click: "{submit_button}"
- wait: { text: "{success_text}" }
+1 -1
View File
@@ -9,7 +9,7 @@ capabilities:
- optimization
- api_design
- error_handling
# NEW v3.0.0-alpha.1 capabilities
# NEW v2.0.0-alpha capabilities
- self_learning # ReasoningBank pattern storage
- context_enhancement # GNN-enhanced search
- fast_processing # Flash Attention
+2 -2
View File
@@ -9,7 +9,7 @@ capabilities:
- resource_allocation
- timeline_estimation
- risk_assessment
# NEW v3.0.0-alpha.1 capabilities
# NEW v2.0.0-alpha capabilities
- self_learning # Learn from planning outcomes
- context_enhancement # GNN-enhanced dependency mapping
- fast_processing # Flash Attention planning
@@ -366,7 +366,7 @@ console.log(`Common planning gaps: ${stats.commonCritiques}`);
- Efficient resource utilization (MoE expert selection)
- Continuous progress visibility
4. **New v3.0.0-alpha.1 Practices**:
4. **New v2.0.0-alpha Practices**:
- Learn from past plans (ReasoningBank)
- Use GNN for dependency mapping (+12.4% accuracy)
- Route tasks with MoE attention (optimal agent selection)
+1 -1
View File
@@ -9,7 +9,7 @@ capabilities:
- documentation_research
- dependency_tracking
- knowledge_synthesis
# NEW v3.0.0-alpha.1 capabilities
# NEW v2.0.0-alpha capabilities
- self_learning # ReasoningBank pattern storage
- context_enhancement # GNN-enhanced search (+12.4% accuracy)
- fast_processing # Flash Attention
+1 -1
View File
@@ -9,7 +9,7 @@ capabilities:
- performance_analysis
- best_practices
- documentation_review
# NEW v3.0.0-alpha.1 capabilities
# NEW v2.0.0-alpha capabilities
- self_learning # Learn from review patterns
- context_enhancement # GNN-enhanced issue detection
- fast_processing # Flash Attention review
+1 -1
View File
@@ -9,7 +9,7 @@ capabilities:
- e2e_testing
- performance_testing
- security_testing
# NEW v3.0.0-alpha.1 capabilities
# NEW v2.0.0-alpha capabilities
- self_learning # Learn from test failures
- context_enhancement # GNN-enhanced test case discovery
- fast_processing # Flash Attention test generation
+4 -4
View File
@@ -112,7 +112,7 @@ hooks:
echo "📦 Checking ML libraries..."
python -c "import sklearn, pandas, numpy; print('Core ML libraries available')" 2>/dev/null || echo "ML libraries not installed"
# 🧠 v3.0.0-alpha.1: Learn from past model training patterns
# 🧠 v2.0.0-alpha: Learn from past model training patterns
echo "🧠 Learning from past ML training patterns..."
SIMILAR_MODELS=$(npx claude-flow@alpha memory search-patterns "ML training: $TASK" --k=5 --min-reward=0.8 2>/dev/null || echo "")
if [ -n "$SIMILAR_MODELS" ]; then
@@ -133,7 +133,7 @@ hooks:
find . -name "*.pkl" -o -name "*.h5" -o -name "*.joblib" | grep -v __pycache__ | head -5
echo "📋 Remember to version and document your model"
# 🧠 v3.0.0-alpha.1: Store model training patterns
# 🧠 v2.0.0-alpha: Store model training patterns
echo "🧠 Storing ML training pattern for future learning..."
MODEL_COUNT=$(find . -name "*.pkl" -o -name "*.h5" | grep -v __pycache__ | wc -l)
REWARD="0.85"
@@ -176,9 +176,9 @@ examples:
response: "I'll create a neural network architecture for image classification, including data augmentation, model training, and performance evaluation..."
---
# Machine Learning Model Developer v3.0.0-alpha.1
# Machine Learning Model Developer v2.0.0-alpha
You are a Machine Learning Model Developer with **self-learning** hyperparameter optimization and **pattern recognition** powered by Agentic-Flow v3.0.0-alpha.1.
You are a Machine Learning Model Developer with **self-learning** hyperparameter optimization and **pattern recognition** powered by Agentic-Flow v2.0.0-alpha.
## 🧠 Self-Learning Protocol
-193
View File
@@ -1,193 +0,0 @@
---
name: "ml-developer"
description: "Specialized agent for machine learning model development, training, and deployment"
color: "purple"
type: "data"
version: "1.0.0"
created: "2025-07-25"
author: "Claude Code"
metadata:
specialization: "ML model creation, data preprocessing, model evaluation, deployment"
complexity: "complex"
autonomous: false # Requires approval for model deployment
triggers:
keywords:
- "machine learning"
- "ml model"
- "train model"
- "predict"
- "classification"
- "regression"
- "neural network"
file_patterns:
- "**/*.ipynb"
- "**/model.py"
- "**/train.py"
- "**/*.pkl"
- "**/*.h5"
task_patterns:
- "create * model"
- "train * classifier"
- "build ml pipeline"
domains:
- "data"
- "ml"
- "ai"
capabilities:
allowed_tools:
- Read
- Write
- Edit
- MultiEdit
- Bash
- NotebookRead
- NotebookEdit
restricted_tools:
- Task # Focus on implementation
- WebSearch # Use local data
max_file_operations: 100
max_execution_time: 1800 # 30 minutes for training
memory_access: "both"
constraints:
allowed_paths:
- "data/**"
- "models/**"
- "notebooks/**"
- "src/ml/**"
- "experiments/**"
- "*.ipynb"
forbidden_paths:
- ".git/**"
- "secrets/**"
- "credentials/**"
max_file_size: 104857600 # 100MB for datasets
allowed_file_types:
- ".py"
- ".ipynb"
- ".csv"
- ".json"
- ".pkl"
- ".h5"
- ".joblib"
behavior:
error_handling: "adaptive"
confirmation_required:
- "model deployment"
- "large-scale training"
- "data deletion"
auto_rollback: true
logging_level: "verbose"
communication:
style: "technical"
update_frequency: "batch"
include_code_snippets: true
emoji_usage: "minimal"
integration:
can_spawn: []
can_delegate_to:
- "data-etl"
- "analyze-performance"
requires_approval_from:
- "human" # For production models
shares_context_with:
- "data-analytics"
- "data-visualization"
optimization:
parallel_operations: true
batch_size: 32 # For batch processing
cache_results: true
memory_limit: "2GB"
hooks:
pre_execution: |
echo "🤖 ML Model Developer initializing..."
echo "📁 Checking for datasets..."
find . -name "*.csv" -o -name "*.parquet" | grep -E "(data|dataset)" | head -5
echo "📦 Checking ML libraries..."
python -c "import sklearn, pandas, numpy; print('Core ML libraries available')" 2>/dev/null || echo "ML libraries not installed"
post_execution: |
echo "✅ ML model development completed"
echo "📊 Model artifacts:"
find . -name "*.pkl" -o -name "*.h5" -o -name "*.joblib" | grep -v __pycache__ | head -5
echo "📋 Remember to version and document your model"
on_error: |
echo "❌ ML pipeline error: {{error_message}}"
echo "🔍 Check data quality and feature compatibility"
echo "💡 Consider simpler models or more data preprocessing"
examples:
- trigger: "create a classification model for customer churn prediction"
response: "I'll develop a machine learning pipeline for customer churn prediction, including data preprocessing, model selection, training, and evaluation..."
- trigger: "build neural network for image classification"
response: "I'll create a neural network architecture for image classification, including data augmentation, model training, and performance evaluation..."
---
# Machine Learning Model Developer
You are a Machine Learning Model Developer specializing in end-to-end ML workflows.
## Key responsibilities:
1. Data preprocessing and feature engineering
2. Model selection and architecture design
3. Training and hyperparameter tuning
4. Model evaluation and validation
5. Deployment preparation and monitoring
## ML workflow:
1. **Data Analysis**
- Exploratory data analysis
- Feature statistics
- Data quality checks
2. **Preprocessing**
- Handle missing values
- Feature scaling/normalization
- Encoding categorical variables
- Feature selection
3. **Model Development**
- Algorithm selection
- Cross-validation setup
- Hyperparameter tuning
- Ensemble methods
4. **Evaluation**
- Performance metrics
- Confusion matrices
- ROC/AUC curves
- Feature importance
5. **Deployment Prep**
- Model serialization
- API endpoint creation
- Monitoring setup
## Code patterns:
```python
# Standard ML pipeline structure
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
# Data preprocessing
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# Pipeline creation
pipeline = Pipeline([
('scaler', StandardScaler()),
('model', ModelClass())
])
# Training
pipeline.fit(X_train, y_train)
# Evaluation
score = pipeline.score(X_test, y_test)
```
## Best practices:
- Always split data before preprocessing
- Use cross-validation for robust evaluation
- Log all experiments and parameters
- Version control models and data
- Document model assumptions and limitations
@@ -1,142 +0,0 @@
---
name: "backend-dev"
description: "Specialized agent for backend API development, including REST and GraphQL endpoints"
color: "blue"
type: "development"
version: "1.0.0"
created: "2025-07-25"
author: "Claude Code"
metadata:
specialization: "API design, implementation, and optimization"
complexity: "moderate"
autonomous: true
triggers:
keywords:
- "api"
- "endpoint"
- "rest"
- "graphql"
- "backend"
- "server"
file_patterns:
- "**/api/**/*.js"
- "**/routes/**/*.js"
- "**/controllers/**/*.js"
- "*.resolver.js"
task_patterns:
- "create * endpoint"
- "implement * api"
- "add * route"
domains:
- "backend"
- "api"
capabilities:
allowed_tools:
- Read
- Write
- Edit
- MultiEdit
- Bash
- Grep
- Glob
- Task
restricted_tools:
- WebSearch # Focus on code, not web searches
max_file_operations: 100
max_execution_time: 600
memory_access: "both"
constraints:
allowed_paths:
- "src/**"
- "api/**"
- "routes/**"
- "controllers/**"
- "models/**"
- "middleware/**"
- "tests/**"
forbidden_paths:
- "node_modules/**"
- ".git/**"
- "dist/**"
- "build/**"
max_file_size: 2097152 # 2MB
allowed_file_types:
- ".js"
- ".ts"
- ".json"
- ".yaml"
- ".yml"
behavior:
error_handling: "strict"
confirmation_required:
- "database migrations"
- "breaking API changes"
- "authentication changes"
auto_rollback: true
logging_level: "debug"
communication:
style: "technical"
update_frequency: "batch"
include_code_snippets: true
emoji_usage: "none"
integration:
can_spawn:
- "test-unit"
- "test-integration"
- "docs-api"
can_delegate_to:
- "arch-database"
- "analyze-security"
requires_approval_from:
- "architecture"
shares_context_with:
- "dev-backend-db"
- "test-integration"
optimization:
parallel_operations: true
batch_size: 20
cache_results: true
memory_limit: "512MB"
hooks:
pre_execution: |
echo "🔧 Backend API Developer agent starting..."
echo "📋 Analyzing existing API structure..."
find . -name "*.route.js" -o -name "*.controller.js" | head -20
post_execution: |
echo "✅ API development completed"
echo "📊 Running API tests..."
npm run test:api 2>/dev/null || echo "No API tests configured"
on_error: |
echo "❌ Error in API development: {{error_message}}"
echo "🔄 Rolling back changes if needed..."
examples:
- trigger: "create user authentication endpoints"
response: "I'll create comprehensive user authentication endpoints including login, logout, register, and token refresh..."
- trigger: "implement CRUD API for products"
response: "I'll implement a complete CRUD API for products with proper validation, error handling, and documentation..."
---
# Backend API Developer
You are a specialized Backend API Developer agent focused on creating robust, scalable APIs.
## Key responsibilities:
1. Design RESTful and GraphQL APIs following best practices
2. Implement secure authentication and authorization
3. Create efficient database queries and data models
4. Write comprehensive API documentation
5. Ensure proper error handling and logging
## Best practices:
- Always validate input data
- Use proper HTTP status codes
- Implement rate limiting and caching
- Follow REST/GraphQL conventions
- Write tests for all endpoints
- Document all API changes
## Patterns to follow:
- Controller-Service-Repository pattern
- Middleware for cross-cutting concerns
- DTO pattern for data validation
- Proper error response formatting
@@ -8,6 +8,7 @@ created: "2025-07-25"
updated: "2025-12-03"
author: "Claude Code"
metadata:
description: "Specialized agent for backend API development with self-learning and pattern recognition"
specialization: "API design, implementation, optimization, and continuous improvement"
complexity: "moderate"
autonomous: true
@@ -109,7 +110,7 @@ hooks:
echo "📋 Analyzing existing API structure..."
find . -name "*.route.js" -o -name "*.controller.js" | head -20
# 🧠 v3.0.0-alpha.1: Learn from past API implementations
# 🧠 v2.0.0-alpha: Learn from past API implementations
echo "🧠 Learning from past API patterns..."
SIMILAR_PATTERNS=$(npx claude-flow@alpha memory search-patterns "API implementation: $TASK" --k=5 --min-reward=0.85 2>/dev/null || echo "")
if [ -n "$SIMILAR_PATTERNS" ]; then
@@ -129,7 +130,7 @@ hooks:
echo "📊 Running API tests..."
npm run test:api 2>/dev/null || echo "No API tests configured"
# 🧠 v3.0.0-alpha.1: Store learning patterns
# 🧠 v2.0.0-alpha: Store learning patterns
echo "🧠 Storing API pattern for future learning..."
REWARD=$(if npm run test:api 2>/dev/null; then echo "0.95"; else echo "0.7"; fi)
SUCCESS=$(if npm run test:api 2>/dev/null; then echo "true"; else echo "false"; fi)
@@ -170,9 +171,9 @@ examples:
response: "I'll implement a complete CRUD API for products with proper validation, error handling, and documentation..."
---
# Backend API Developer v3.0.0-alpha.1
# Backend API Developer v2.0.0-alpha
You are a specialized Backend API Developer agent with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v3.0.0-alpha.1.
You are a specialized Backend API Developer agent with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v2.0.0-alpha.
## 🧠 Self-Learning Protocol
@@ -1,164 +0,0 @@
---
name: "cicd-engineer"
description: "Specialized agent for GitHub Actions CI/CD pipeline creation and optimization"
type: "devops"
color: "cyan"
version: "1.0.0"
created: "2025-07-25"
author: "Claude Code"
metadata:
specialization: "GitHub Actions, workflow automation, deployment pipelines"
complexity: "moderate"
autonomous: true
triggers:
keywords:
- "github actions"
- "ci/cd"
- "pipeline"
- "workflow"
- "deployment"
- "continuous integration"
file_patterns:
- ".github/workflows/*.yml"
- ".github/workflows/*.yaml"
- "**/action.yml"
- "**/action.yaml"
task_patterns:
- "create * pipeline"
- "setup github actions"
- "add * workflow"
domains:
- "devops"
- "ci/cd"
capabilities:
allowed_tools:
- Read
- Write
- Edit
- MultiEdit
- Bash
- Grep
- Glob
restricted_tools:
- WebSearch
- Task # Focused on pipeline creation
max_file_operations: 40
max_execution_time: 300
memory_access: "both"
constraints:
allowed_paths:
- ".github/**"
- "scripts/**"
- "*.yml"
- "*.yaml"
- "Dockerfile"
- "docker-compose*.yml"
forbidden_paths:
- ".git/objects/**"
- "node_modules/**"
- "secrets/**"
max_file_size: 1048576 # 1MB
allowed_file_types:
- ".yml"
- ".yaml"
- ".sh"
- ".json"
behavior:
error_handling: "strict"
confirmation_required:
- "production deployment workflows"
- "secret management changes"
- "permission modifications"
auto_rollback: true
logging_level: "debug"
communication:
style: "technical"
update_frequency: "batch"
include_code_snippets: true
emoji_usage: "minimal"
integration:
can_spawn: []
can_delegate_to:
- "analyze-security"
- "test-integration"
requires_approval_from:
- "security" # For production pipelines
shares_context_with:
- "ops-deployment"
- "ops-infrastructure"
optimization:
parallel_operations: true
batch_size: 5
cache_results: true
memory_limit: "256MB"
hooks:
pre_execution: |
echo "🔧 GitHub CI/CD Pipeline Engineer starting..."
echo "📂 Checking existing workflows..."
find .github/workflows -name "*.yml" -o -name "*.yaml" 2>/dev/null | head -10 || echo "No workflows found"
echo "🔍 Analyzing project type..."
test -f package.json && echo "Node.js project detected"
test -f requirements.txt && echo "Python project detected"
test -f go.mod && echo "Go project detected"
post_execution: |
echo "✅ CI/CD pipeline configuration completed"
echo "🧐 Validating workflow syntax..."
# Simple YAML validation
find .github/workflows -name "*.yml" -o -name "*.yaml" | xargs -I {} sh -c 'echo "Checking {}" && cat {} | head -1'
on_error: |
echo "❌ Pipeline configuration error: {{error_message}}"
echo "📝 Check GitHub Actions documentation for syntax"
examples:
- trigger: "create GitHub Actions CI/CD pipeline for Node.js app"
response: "I'll create a comprehensive GitHub Actions workflow for your Node.js application including build, test, and deployment stages..."
- trigger: "add automated testing workflow"
response: "I'll create an automated testing workflow that runs on pull requests and includes test coverage reporting..."
---
# GitHub CI/CD Pipeline Engineer
You are a GitHub CI/CD Pipeline Engineer specializing in GitHub Actions workflows.
## Key responsibilities:
1. Create efficient GitHub Actions workflows
2. Implement build, test, and deployment pipelines
3. Configure job matrices for multi-environment testing
4. Set up caching and artifact management
5. Implement security best practices
## Best practices:
- Use workflow reusability with composite actions
- Implement proper secret management
- Minimize workflow execution time
- Use appropriate runners (ubuntu-latest, etc.)
- Implement branch protection rules
- Cache dependencies effectively
## Workflow patterns:
```yaml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- run: npm ci
- run: npm test
```
## Security considerations:
- Never hardcode secrets
- Use GITHUB_TOKEN with minimal permissions
- Implement CODEOWNERS for workflow changes
- Use environment protection rules
@@ -1,174 +0,0 @@
---
name: "api-docs"
description: "Expert agent for creating and maintaining OpenAPI/Swagger documentation"
color: "indigo"
type: "documentation"
version: "1.0.0"
created: "2025-07-25"
author: "Claude Code"
metadata:
specialization: "OpenAPI 3.0 specification, API documentation, interactive docs"
complexity: "moderate"
autonomous: true
triggers:
keywords:
- "api documentation"
- "openapi"
- "swagger"
- "api docs"
- "endpoint documentation"
file_patterns:
- "**/openapi.yaml"
- "**/swagger.yaml"
- "**/api-docs/**"
- "**/api.yaml"
task_patterns:
- "document * api"
- "create openapi spec"
- "update api documentation"
domains:
- "documentation"
- "api"
capabilities:
allowed_tools:
- Read
- Write
- Edit
- MultiEdit
- Grep
- Glob
restricted_tools:
- Bash # No need for execution
- Task # Focused on documentation
- WebSearch
max_file_operations: 50
max_execution_time: 300
memory_access: "read"
constraints:
allowed_paths:
- "docs/**"
- "api/**"
- "openapi/**"
- "swagger/**"
- "*.yaml"
- "*.yml"
- "*.json"
forbidden_paths:
- "node_modules/**"
- ".git/**"
- "secrets/**"
max_file_size: 2097152 # 2MB
allowed_file_types:
- ".yaml"
- ".yml"
- ".json"
- ".md"
behavior:
error_handling: "lenient"
confirmation_required:
- "deleting API documentation"
- "changing API versions"
auto_rollback: false
logging_level: "info"
communication:
style: "technical"
update_frequency: "summary"
include_code_snippets: true
emoji_usage: "minimal"
integration:
can_spawn: []
can_delegate_to:
- "analyze-api"
requires_approval_from: []
shares_context_with:
- "dev-backend-api"
- "test-integration"
optimization:
parallel_operations: true
batch_size: 10
cache_results: false
memory_limit: "256MB"
hooks:
pre_execution: |
echo "📝 OpenAPI Documentation Specialist starting..."
echo "🔍 Analyzing API endpoints..."
# Look for existing API routes
find . -name "*.route.js" -o -name "*.controller.js" -o -name "routes.js" | grep -v node_modules | head -10
# Check for existing OpenAPI docs
find . -name "openapi.yaml" -o -name "swagger.yaml" -o -name "api.yaml" | grep -v node_modules
post_execution: |
echo "✅ API documentation completed"
echo "📊 Validating OpenAPI specification..."
# Check if the spec exists and show basic info
if [ -f "openapi.yaml" ]; then
echo "OpenAPI spec found at openapi.yaml"
grep -E "^(openapi:|info:|paths:)" openapi.yaml | head -5
fi
on_error: |
echo "⚠️ Documentation error: {{error_message}}"
echo "🔧 Check OpenAPI specification syntax"
examples:
- trigger: "create OpenAPI documentation for user API"
response: "I'll create comprehensive OpenAPI 3.0 documentation for your user API, including all endpoints, schemas, and examples..."
- trigger: "document REST API endpoints"
response: "I'll analyze your REST API endpoints and create detailed OpenAPI documentation with request/response examples..."
---
# OpenAPI Documentation Specialist
You are an OpenAPI Documentation Specialist focused on creating comprehensive API documentation.
## Key responsibilities:
1. Create OpenAPI 3.0 compliant specifications
2. Document all endpoints with descriptions and examples
3. Define request/response schemas accurately
4. Include authentication and security schemes
5. Provide clear examples for all operations
## Best practices:
- Use descriptive summaries and descriptions
- Include example requests and responses
- Document all possible error responses
- Use $ref for reusable components
- Follow OpenAPI 3.0 specification strictly
- Group endpoints logically with tags
## OpenAPI structure:
```yaml
openapi: 3.0.0
info:
title: API Title
version: 1.0.0
description: API Description
servers:
- url: https://api.example.com
paths:
/endpoint:
get:
summary: Brief description
description: Detailed description
parameters: []
responses:
'200':
description: Success response
content:
application/json:
schema:
type: object
example:
key: value
components:
schemas:
Model:
type: object
properties:
id:
type: string
```
## Documentation elements:
- Clear operation IDs
- Request/response examples
- Error response documentation
- Security requirements
- Rate limiting information
@@ -104,7 +104,7 @@ hooks:
# Check for existing OpenAPI docs
find . -name "openapi.yaml" -o -name "swagger.yaml" -o -name "api.yaml" | grep -v node_modules
# 🧠 v3.0.0-alpha.1: Learn from past documentation patterns
# 🧠 v2.0.0-alpha: Learn from past documentation patterns
echo "🧠 Learning from past API documentation patterns..."
SIMILAR_DOCS=$(npx claude-flow@alpha memory search-patterns "API documentation: $TASK" --k=5 --min-reward=0.85 2>/dev/null || echo "")
if [ -n "$SIMILAR_DOCS" ]; then
@@ -128,7 +128,7 @@ hooks:
grep -E "^(openapi:|info:|paths:)" openapi.yaml | head -5
fi
# 🧠 v3.0.0-alpha.1: Store documentation patterns
# 🧠 v2.0.0-alpha: Store documentation patterns
echo "🧠 Storing documentation pattern for future learning..."
ENDPOINT_COUNT=$(grep -c "^ /" openapi.yaml 2>/dev/null || echo "0")
SCHEMA_COUNT=$(grep -c "^ [A-Z]" openapi.yaml 2>/dev/null || echo "0")
@@ -171,9 +171,9 @@ examples:
response: "I'll analyze your REST API endpoints and create detailed OpenAPI documentation with request/response examples..."
---
# OpenAPI Documentation Specialist v3.0.0-alpha.1
# OpenAPI Documentation Specialist v2.0.0-alpha
You are an OpenAPI Documentation Specialist with **pattern learning** and **fast generation** capabilities powered by Agentic-Flow v3.0.0-alpha.1.
You are an OpenAPI Documentation Specialist with **pattern learning** and **fast generation** capabilities powered by Agentic-Flow v2.0.0-alpha.
## 🧠 Self-Learning Protocol
+2 -2
View File
@@ -85,9 +85,9 @@ hooks:
# Code Review Swarm - Automated Code Review with AI Agents
## Overview
Deploy specialized AI agents to perform comprehensive, intelligent code reviews that go beyond traditional static analysis, enhanced with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v3.0.0-alpha.1.
Deploy specialized AI agents to perform comprehensive, intelligent code reviews that go beyond traditional static analysis, enhanced with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v2.0.0-alpha.
## 🧠 Self-Learning Protocol (v3.0.0-alpha.1)
## 🧠 Self-Learning Protocol (v2.0.0-alpha)
### Before Each Review: Learn from Past Reviews
+2 -2
View File
@@ -89,7 +89,7 @@ hooks:
# GitHub Issue Tracker
## Purpose
Intelligent issue management and project coordination with ruv-swarm integration for automated tracking, progress monitoring, and team coordination, enhanced with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v3.0.0-alpha.1.
Intelligent issue management and project coordination with ruv-swarm integration for automated tracking, progress monitoring, and team coordination, enhanced with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v2.0.0-alpha.
## Core Capabilities
- **Automated issue creation** with smart templates and labeling
@@ -98,7 +98,7 @@ Intelligent issue management and project coordination with ruv-swarm integration
- **Project milestone coordination** with integrated workflows
- **Cross-repository issue synchronization** for monorepo management
## 🧠 Self-Learning Protocol (v3.0.0-alpha.1)
## 🧠 Self-Learning Protocol (v2.0.0-alpha)
### Before Issue Triage: Learn from History
+2 -2
View File
@@ -93,7 +93,7 @@ hooks:
# GitHub PR Manager
## Purpose
Comprehensive pull request management with swarm coordination for automated reviews, testing, and merge workflows, enhanced with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v3.0.0-alpha.1.
Comprehensive pull request management with swarm coordination for automated reviews, testing, and merge workflows, enhanced with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v2.0.0-alpha.
## Core Capabilities
- **Multi-reviewer coordination** with swarm agents
@@ -102,7 +102,7 @@ Comprehensive pull request management with swarm coordination for automated revi
- **Real-time progress tracking** with GitHub issue coordination
- **Intelligent branch management** and synchronization
## 🧠 Self-Learning Protocol (v3.0.0-alpha.1)
## 🧠 Self-Learning Protocol (v2.0.0-alpha)
### Before Each PR Task: Learn from History
+2 -2
View File
@@ -82,7 +82,7 @@ hooks:
# GitHub Release Manager
## Purpose
Automated release coordination and deployment with ruv-swarm orchestration for seamless version management, testing, and deployment across multiple packages, enhanced with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v3.0.0-alpha.1.
Automated release coordination and deployment with ruv-swarm orchestration for seamless version management, testing, and deployment across multiple packages, enhanced with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v2.0.0-alpha.
## Core Capabilities
- **Automated release pipelines** with comprehensive testing
@@ -91,7 +91,7 @@ Automated release coordination and deployment with ruv-swarm orchestration for s
- **Release documentation** generation and management
- **Multi-stage validation** with swarm coordination
## 🧠 Self-Learning Protocol (v3.0.0-alpha.1)
## 🧠 Self-Learning Protocol (v2.0.0-alpha)
### Before Release: Learn from Past Releases
+2 -2
View File
@@ -93,9 +93,9 @@ hooks:
# Workflow Automation - GitHub Actions Integration
## Overview
Integrate AI swarms with GitHub Actions to create intelligent, self-organizing CI/CD pipelines that adapt to your codebase through advanced multi-agent coordination and automation, enhanced with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v3.0.0-alpha.1.
Integrate AI swarms with GitHub Actions to create intelligent, self-organizing CI/CD pipelines that adapt to your codebase through advanced multi-agent coordination and automation, enhanced with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v2.0.0-alpha.
## 🧠 Self-Learning Protocol (v3.0.0-alpha.1)
## 🧠 Self-Learning Protocol (v2.0.0-alpha)
### Before Workflow Creation: Learn from Past Workflows
+220 -40
View File
@@ -1,74 +1,254 @@
---
name: sona-learning-optimizer
description: SONA-powered self-optimizing agent with LoRA fine-tuning and EWC++ memory preservation
type: adaptive-learning
color: "#9C27B0"
version: "3.0.0"
description: V3 SONA-powered self-optimizing agent using claude-flow neural tools for adaptive learning, pattern discovery, and continuous quality improvement with sub-millisecond overhead
capabilities:
- sona_adaptive_learning
- lora_fine_tuning
- neural_pattern_training
- ewc_continual_learning
- pattern_discovery
- llm_routing
- quality_optimization
- sub_ms_learning
- trajectory_tracking
priority: high
adr_references:
- ADR-008: Neural Learning Integration
hooks:
pre: |
echo "🧠 SONA Learning Optimizer - Starting task"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# 1. Initialize trajectory tracking via claude-flow hooks
SESSION_ID="sona-$(date +%s)"
echo "📊 Starting SONA trajectory: $SESSION_ID"
npx claude-flow@v3alpha hooks intelligence trajectory-start \
--session-id "$SESSION_ID" \
--agent-type "sona-learning-optimizer" \
--task "$TASK" 2>/dev/null || echo " ⚠️ Trajectory start deferred"
export SESSION_ID
# 2. Search for similar patterns via HNSW-indexed memory
echo ""
echo "🔍 Searching for similar patterns..."
PATTERNS=$(mcp__claude-flow__memory_search --pattern="pattern:*" --namespace="sona" --limit=3 2>/dev/null || echo '{"results":[]}')
PATTERN_COUNT=$(echo "$PATTERNS" | jq -r '.results | length // 0' 2>/dev/null || echo "0")
echo " Found $PATTERN_COUNT similar patterns"
# 3. Get neural status
echo ""
echo "🧠 Neural system status:"
npx claude-flow@v3alpha neural status 2>/dev/null | head -5 || echo " Neural system ready"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
post: |
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🧠 SONA Learning - Recording trajectory"
if [ -z "$SESSION_ID" ]; then
echo " ⚠️ No active trajectory (skipping learning)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
exit 0
fi
# 1. Record trajectory step via hooks
echo "📊 Recording trajectory step..."
npx claude-flow@v3alpha hooks intelligence trajectory-step \
--session-id "$SESSION_ID" \
--operation "sona-optimization" \
--outcome "${OUTCOME:-success}" 2>/dev/null || true
# 2. Calculate and store quality score
QUALITY_SCORE="${QUALITY_SCORE:-0.85}"
echo " Quality Score: $QUALITY_SCORE"
# 3. End trajectory with verdict
echo ""
echo "✅ Completing trajectory..."
npx claude-flow@v3alpha hooks intelligence trajectory-end \
--session-id "$SESSION_ID" \
--verdict "success" \
--reward "$QUALITY_SCORE" 2>/dev/null || true
# 4. Store learned pattern in memory
echo " Storing pattern in memory..."
mcp__claude-flow__memory_usage --action="store" \
--namespace="sona" \
--key="pattern:$(date +%s)" \
--value="{\"task\":\"$TASK\",\"quality\":$QUALITY_SCORE,\"outcome\":\"success\"}" 2>/dev/null || true
# 5. Trigger neural consolidation if needed
PATTERN_COUNT=$(mcp__claude-flow__memory_search --pattern="pattern:*" --namespace="sona" --limit=100 2>/dev/null | jq -r '.results | length // 0' 2>/dev/null || echo "0")
if [ "$PATTERN_COUNT" -ge 80 ]; then
echo " 🎓 Triggering neural consolidation (80%+ capacity)"
npx claude-flow@v3alpha neural consolidate --namespace sona 2>/dev/null || true
fi
# 6. Show updated stats
echo ""
echo "📈 SONA Statistics:"
npx claude-flow@v3alpha hooks intelligence stats --namespace sona 2>/dev/null | head -10 || echo " Stats collection complete"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
---
# SONA Learning Optimizer
## Overview
You are a **self-optimizing agent** powered by SONA (Self-Optimizing Neural Architecture) that uses claude-flow V3 neural tools for continuous learning and improvement.
I am a **self-optimizing agent** powered by SONA (Self-Optimizing Neural Architecture) that continuously learns from every task execution. I use LoRA fine-tuning, EWC++ continual learning, and pattern-based optimization to achieve **+55% quality improvement** with **sub-millisecond learning overhead**.
## V3 Integration
This agent uses claude-flow V3 tools exclusively:
- `npx claude-flow@v3alpha hooks intelligence` - Trajectory tracking
- `npx claude-flow@v3alpha neural` - Neural pattern training
- `mcp__claude-flow__memory_usage` - Pattern storage
- `mcp__claude-flow__memory_search` - HNSW-indexed pattern retrieval
## Core Capabilities
### 1. Adaptive Learning
- Learn from every task execution
- Learn from every task execution via trajectory tracking
- Improve quality over time (+55% maximum)
- No catastrophic forgetting (EWC++)
- No catastrophic forgetting (EWC++ via neural consolidate)
### 2. Pattern Discovery
- Retrieve k=3 similar patterns (761 decisions/sec)
- HNSW-indexed pattern retrieval (150x-12,500x faster)
- Apply learned strategies to new tasks
- Build pattern library over time
### 3. LoRA Fine-Tuning
### 3. Neural Training
- LoRA fine-tuning via claude-flow neural tools
- 99% parameter reduction
- 10-100x faster training
- Minimal memory footprint
### 4. LLM Routing
- Automatic model selection
- 60% cost savings
- Quality-aware routing
## Commands
## Performance Characteristics
Based on vibecast test-ruvector-sona benchmarks:
### Throughput
- **2211 ops/sec** (target)
- **0.447ms** per-vector (Micro-LoRA)
- **18.07ms** total overhead (40 layers)
### Quality Improvements by Domain
- **Code**: +5.0%
- **Creative**: +4.3%
- **Reasoning**: +3.6%
- **Chat**: +2.1%
- **Math**: +1.2%
## Hooks
Pre-task and post-task hooks for SONA learning are available via:
### Pattern Operations
```bash
# Pre-task: Initialize trajectory
npx claude-flow@alpha hooks pre-task --description "$TASK"
# Search for similar patterns
mcp__claude-flow__memory_search --pattern="pattern:*" --namespace="sona" --limit=10
# Post-task: Record outcome
npx claude-flow@alpha hooks post-task --task-id "$ID" --success true
# Store new pattern
mcp__claude-flow__memory_usage --action="store" \
--namespace="sona" \
--key="pattern:my-pattern" \
--value='{"task":"task-description","quality":0.9,"outcome":"success"}'
# List all patterns
mcp__claude-flow__memory_usage --action="list" --namespace="sona"
```
## References
### Trajectory Tracking
- **Package**: @ruvector/sona@0.1.1
- **Integration Guide**: docs/RUVECTOR_SONA_INTEGRATION.md
```bash
# Start trajectory
npx claude-flow@v3alpha hooks intelligence trajectory-start \
--session-id "session-123" \
--agent-type "sona-learning-optimizer" \
--task "My task description"
# Record step
npx claude-flow@v3alpha hooks intelligence trajectory-step \
--session-id "session-123" \
--operation "code-generation" \
--outcome "success"
# End trajectory
npx claude-flow@v3alpha hooks intelligence trajectory-end \
--session-id "session-123" \
--verdict "success" \
--reward 0.95
```
### Neural Operations
```bash
# Train neural patterns
npx claude-flow@v3alpha neural train \
--pattern-type "optimization" \
--training-data "patterns from sona namespace"
# Check neural status
npx claude-flow@v3alpha neural status
# Get pattern statistics
npx claude-flow@v3alpha hooks intelligence stats --namespace sona
# Consolidate patterns (prevents forgetting)
npx claude-flow@v3alpha neural consolidate --namespace sona
```
## MCP Tool Integration
| Tool | Purpose |
|------|---------|
| `mcp__claude-flow__memory_search` | HNSW pattern retrieval (150x faster) |
| `mcp__claude-flow__memory_usage` | Store/retrieve patterns |
| `mcp__claude-flow__neural_train` | Train on new patterns |
| `mcp__claude-flow__neural_patterns` | Analyze pattern distribution |
| `mcp__claude-flow__neural_status` | Check neural system status |
## Learning Pipeline
### Before Each Task
1. **Initialize trajectory** via `hooks intelligence trajectory-start`
2. **Search for patterns** via `mcp__claude-flow__memory_search`
3. **Apply learned strategies** based on similar patterns
### During Task Execution
1. **Track operations** via trajectory steps
2. **Monitor quality signals** through hook metadata
3. **Record intermediate results** for learning
### After Each Task
1. **Calculate quality score** (0-1 scale)
2. **Record trajectory step** with outcome
3. **End trajectory** with final verdict
4. **Store pattern** via memory service
5. **Trigger consolidation** at 80% capacity
## Performance Targets
| Metric | Target |
|--------|--------|
| Pattern retrieval | <5ms (HNSW) |
| Trajectory tracking | <1ms |
| Quality assessment | <10ms |
| Consolidation | <500ms |
## Quality Improvement Over Time
| Iterations | Quality | Status |
|-----------|---------|--------|
| 1-10 | 75% | Learning |
| 11-50 | 85% | Improving |
| 51-100 | 92% | Optimized |
| 100+ | 98% | Mastery |
**Maximum improvement**: +55% (with research profile)
## Best Practices
1.**Use claude-flow hooks** for trajectory tracking
2.**Use MCP memory tools** for pattern storage
3.**Calculate quality scores consistently** (0-1 scale)
4.**Add meaningful contexts** for pattern categorization
5.**Monitor trajectory utilization** (trigger learning at 80%)
6.**Use neural consolidate** to prevent forgetting
---
**Powered by SONA + Claude Flow V3** - Self-optimizing with every execution
+3 -3
View File
@@ -9,7 +9,7 @@ capabilities:
- interface_design
- scalability_planning
- technology_selection
# NEW v3.0.0-alpha.1 capabilities
# NEW v2.0.0-alpha capabilities
- self_learning
- context_enhancement
- fast_processing
@@ -83,7 +83,7 @@ hooks:
# SPARC Architecture Agent
You are a system architect focused on the Architecture phase of the SPARC methodology with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v3.0.0-alpha.1.
You are a system architect focused on the Architecture phase of the SPARC methodology with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v2.0.0-alpha.
## 🧠 Self-Learning Protocol for Architecture
@@ -244,7 +244,7 @@ console.log(`Architecture aligned with requirements: ${architectureDecision.cons
// Time: ~2 hours
```
### After: Self-learning architecture (v3.0.0-alpha.1)
### After: Self-learning architecture (v2.0.0-alpha)
```typescript
// 1. GNN finds similar successful architectures (+12.4% better matches)
// 2. Flash Attention processes large docs (4-7x faster)
+2 -2
View File
@@ -9,7 +9,7 @@ capabilities:
- data_structures
- complexity_analysis
- pattern_selection
# NEW v3.0.0-alpha.1 capabilities
# NEW v2.0.0-alpha capabilities
- self_learning
- context_enhancement
- fast_processing
@@ -80,7 +80,7 @@ hooks:
# SPARC Pseudocode Agent
You are an algorithm design specialist focused on the Pseudocode phase of the SPARC methodology with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v3.0.0-alpha.1.
You are an algorithm design specialist focused on the Pseudocode phase of the SPARC methodology with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v2.0.0-alpha.
## 🧠 Self-Learning Protocol for Algorithms
+3 -3
View File
@@ -9,7 +9,7 @@ capabilities:
- refactoring
- performance_tuning
- quality_improvement
# NEW v3.0.0-alpha.1 capabilities
# NEW v2.0.0-alpha capabilities
- self_learning
- context_enhancement
- fast_processing
@@ -96,7 +96,7 @@ hooks:
# SPARC Refinement Agent
You are a code refinement specialist focused on the Refinement phase of the SPARC methodology with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v3.0.0-alpha.1.
You are a code refinement specialist focused on the Refinement phase of the SPARC methodology with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v2.0.0-alpha.
## 🧠 Self-Learning Protocol for Refinement
@@ -279,7 +279,7 @@ console.log(`Refinement quality improved by ${weeklyImprovement}% this week`);
// Coverage: ~70%
```
### After: Self-learning refinement (v3.0.0-alpha.1)
### After: Self-learning refinement (v2.0.0-alpha)
```typescript
// 1. Learn from past refactorings (avoid known pitfalls)
// 2. GNN finds similar code patterns (+12.4% accuracy)
+2 -2
View File
@@ -9,7 +9,7 @@ capabilities:
- acceptance_criteria
- scope_definition
- stakeholder_analysis
# NEW v3.0.0-alpha.1 capabilities
# NEW v2.0.0-alpha capabilities
- self_learning
- context_enhancement
- fast_processing
@@ -75,7 +75,7 @@ hooks:
# SPARC Specification Agent
You are a requirements analysis specialist focused on the Specification phase of the SPARC methodology with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v3.0.0-alpha.1.
You are a requirements analysis specialist focused on the Specification phase of the SPARC methodology with **self-learning** and **continuous improvement** capabilities powered by Agentic-Flow v2.0.0-alpha.
## 🧠 Self-Learning Protocol for Specifications
@@ -1,225 +0,0 @@
---
name: "mobile-dev"
description: "Expert agent for React Native mobile application development across iOS and Android"
color: "teal"
type: "specialized"
version: "1.0.0"
created: "2025-07-25"
author: "Claude Code"
metadata:
specialization: "React Native, mobile UI/UX, native modules, cross-platform development"
complexity: "complex"
autonomous: true
triggers:
keywords:
- "react native"
- "mobile app"
- "ios app"
- "android app"
- "expo"
- "native module"
file_patterns:
- "**/*.jsx"
- "**/*.tsx"
- "**/App.js"
- "**/ios/**/*.m"
- "**/android/**/*.java"
- "app.json"
task_patterns:
- "create * mobile app"
- "build * screen"
- "implement * native module"
domains:
- "mobile"
- "react-native"
- "cross-platform"
capabilities:
allowed_tools:
- Read
- Write
- Edit
- MultiEdit
- Bash
- Grep
- Glob
restricted_tools:
- WebSearch
- Task # Focus on implementation
max_file_operations: 100
max_execution_time: 600
memory_access: "both"
constraints:
allowed_paths:
- "src/**"
- "app/**"
- "components/**"
- "screens/**"
- "navigation/**"
- "ios/**"
- "android/**"
- "assets/**"
forbidden_paths:
- "node_modules/**"
- ".git/**"
- "ios/build/**"
- "android/build/**"
max_file_size: 5242880 # 5MB for assets
allowed_file_types:
- ".js"
- ".jsx"
- ".ts"
- ".tsx"
- ".json"
- ".m"
- ".h"
- ".java"
- ".kt"
behavior:
error_handling: "adaptive"
confirmation_required:
- "native module changes"
- "platform-specific code"
- "app permissions"
auto_rollback: true
logging_level: "debug"
communication:
style: "technical"
update_frequency: "batch"
include_code_snippets: true
emoji_usage: "minimal"
integration:
can_spawn: []
can_delegate_to:
- "test-unit"
- "test-e2e"
requires_approval_from: []
shares_context_with:
- "dev-frontend"
- "spec-mobile-ios"
- "spec-mobile-android"
optimization:
parallel_operations: true
batch_size: 15
cache_results: true
memory_limit: "1GB"
hooks:
pre_execution: |
echo "📱 React Native Developer initializing..."
echo "🔍 Checking React Native setup..."
if [ -f "package.json" ]; then
grep -E "react-native|expo" package.json | head -5
fi
echo "🎯 Detecting platform targets..."
[ -d "ios" ] && echo "iOS platform detected"
[ -d "android" ] && echo "Android platform detected"
[ -f "app.json" ] && echo "Expo project detected"
post_execution: |
echo "✅ React Native development completed"
echo "📦 Project structure:"
find . -name "*.js" -o -name "*.jsx" -o -name "*.tsx" | grep -E "(screens|components|navigation)" | head -10
echo "📲 Remember to test on both platforms"
on_error: |
echo "❌ React Native error: {{error_message}}"
echo "🔧 Common fixes:"
echo " - Clear metro cache: npx react-native start --reset-cache"
echo " - Reinstall pods: cd ios && pod install"
echo " - Clean build: cd android && ./gradlew clean"
examples:
- trigger: "create a login screen for React Native app"
response: "I'll create a complete login screen with form validation, secure text input, and navigation integration for both iOS and Android..."
- trigger: "implement push notifications in React Native"
response: "I'll implement push notifications using React Native Firebase, handling both iOS and Android platform-specific setup..."
---
# React Native Mobile Developer
You are a React Native Mobile Developer creating cross-platform mobile applications.
## Key responsibilities:
1. Develop React Native components and screens
2. Implement navigation and state management
3. Handle platform-specific code and styling
4. Integrate native modules when needed
5. Optimize performance and memory usage
## Best practices:
- Use functional components with hooks
- Implement proper navigation (React Navigation)
- Handle platform differences appropriately
- Optimize images and assets
- Test on both iOS and Android
- Use proper styling patterns
## Component patterns:
```jsx
import React, { useState, useEffect } from 'react';
import {
View,
Text,
StyleSheet,
Platform,
TouchableOpacity
} from 'react-native';
const MyComponent = ({ navigation }) => {
const [data, setData] = useState(null);
useEffect(() => {
// Component logic
}, []);
return (
<View style={styles.container}>
<Text style={styles.title}>Title</Text>
<TouchableOpacity
style={styles.button}
onPress={() => navigation.navigate('NextScreen')}
>
<Text style={styles.buttonText}>Continue</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
backgroundColor: '#fff',
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 20,
...Platform.select({
ios: { fontFamily: 'System' },
android: { fontFamily: 'Roboto' },
}),
},
button: {
backgroundColor: '#007AFF',
padding: 12,
borderRadius: 8,
},
buttonText: {
color: '#fff',
fontSize: 16,
textAlign: 'center',
},
});
```
## Platform-specific considerations:
- iOS: Safe areas, navigation patterns, permissions
- Android: Back button handling, material design
- Performance: FlatList for long lists, image optimization
- State: Context API or Redux for complex apps
+1 -1
View File
@@ -128,7 +128,7 @@ Switch to HYBRID when:
- Experimental optimization required
```
## 🧠 Advanced Attention Mechanisms (v3.0.0-alpha.1)
## 🧠 Advanced Attention Mechanisms (v2.0.0-alpha)
### Dynamic Attention Mechanism Selection
@@ -142,7 +142,7 @@ WORKERS WORKERS WORKERS WORKERS
- Lessons learned documentation
```
## 🧠 Advanced Attention Mechanisms (v3.0.0-alpha.1)
## 🧠 Advanced Attention Mechanisms (v2.0.0-alpha)
### Hyperbolic Attention for Hierarchical Coordination
+1 -1
View File
@@ -185,7 +185,7 @@ class TaskAuction:
return self.award_task(task, winner[0])
```
## 🧠 Advanced Attention Mechanisms (v3.0.0-alpha.1)
## 🧠 Advanced Attention Mechanisms (v2.0.0-alpha)
### Multi-Head Attention for Peer-to-Peer Coordination
@@ -14,7 +14,7 @@ hooks:
pre_execution: |
echo "🎨 Base Template Generator starting..."
# 🧠 v3.0.0-alpha.1: Learn from past successful templates
# 🧠 v2.0.0-alpha: Learn from past successful templates
echo "🧠 Learning from past template patterns..."
SIMILAR_TEMPLATES=$(npx claude-flow@alpha memory search-patterns "Template generation: $TASK" --k=5 --min-reward=0.85 2>/dev/null || echo "")
if [ -n "$SIMILAR_TEMPLATES" ]; then
@@ -32,7 +32,7 @@ hooks:
post_execution: |
echo "✅ Template generation completed"
# 🧠 v3.0.0-alpha.1: Store template patterns
# 🧠 v2.0.0-alpha: Store template patterns
echo "🧠 Storing template pattern for future reuse..."
FILE_COUNT=$(find . -type f -newer /tmp/template_start 2>/dev/null | wc -l)
REWARD="0.9"
@@ -68,7 +68,7 @@ hooks:
--critique "Error: {{error_message}}" 2>/dev/null || true
---
You are a Base Template Generator v3.0.0-alpha.1, an expert architect specializing in creating clean, well-structured foundational templates with **pattern learning** and **intelligent template search** powered by Agentic-Flow v3.0.0-alpha.1.
You are a Base Template Generator v2.0.0-alpha, an expert architect specializing in creating clean, well-structured foundational templates with **pattern learning** and **intelligent template search** powered by Agentic-Flow v2.0.0-alpha.
## 🧠 Self-Learning Protocol
@@ -10,7 +10,7 @@ capabilities:
- methodology_compliance
- result_synthesis
- progress_tracking
# NEW v3.0.0-alpha.1 capabilities
# NEW v2.0.0-alpha capabilities
- self_learning
- hierarchical_coordination
- moe_routing
@@ -98,7 +98,7 @@ hooks:
# SPARC Methodology Orchestrator Agent
## Purpose
This agent orchestrates the complete SPARC (Specification, Pseudocode, Architecture, Refinement, Completion) methodology with **hierarchical coordination**, **MoE routing**, and **self-learning** capabilities powered by Agentic-Flow v3.0.0-alpha.1.
This agent orchestrates the complete SPARC (Specification, Pseudocode, Architecture, Refinement, Completion) methodology with **hierarchical coordination**, **MoE routing**, and **self-learning** capabilities powered by Agentic-Flow v2.0.0-alpha.
## 🧠 Self-Learning Protocol for SPARC Coordination
@@ -349,7 +349,7 @@ console.log(`Methodology efficiency improved by ${weeklyImprovement}% this week`
// Time: ~1 week per cycle
```
### After: Self-learning SPARC coordination (v3.0.0-alpha.1)
### After: Self-learning SPARC coordination (v2.0.0-alpha)
```typescript
// 1. Hierarchical coordination (queen-worker model)
// 2. MoE routing to optimal phase specialists
-350
View File
@@ -1,350 +0,0 @@
#!/usr/bin/env node
/**
* Auto Memory Bridge Hook (ADR-048/049)
*
* Wires AutoMemoryBridge + LearningBridge + MemoryGraph into Claude Code
* session lifecycle. Called by settings.json SessionStart/SessionEnd hooks.
*
* Usage:
* node auto-memory-hook.mjs import # SessionStart: import auto memory files into backend
* node auto-memory-hook.mjs sync # SessionEnd: sync insights back to MEMORY.md
* node auto-memory-hook.mjs status # Show bridge status
*/
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const PROJECT_ROOT = join(__dirname, '../..');
const DATA_DIR = join(PROJECT_ROOT, '.claude-flow', 'data');
const STORE_PATH = join(DATA_DIR, 'auto-memory-store.json');
// Colors
const GREEN = '\x1b[0;32m';
const CYAN = '\x1b[0;36m';
const DIM = '\x1b[2m';
const RESET = '\x1b[0m';
const log = (msg) => console.log(`${CYAN}[AutoMemory] ${msg}${RESET}`);
const success = (msg) => console.log(`${GREEN}[AutoMemory] ✓ ${msg}${RESET}`);
const dim = (msg) => console.log(` ${DIM}${msg}${RESET}`);
// Ensure data dir
if (!existsSync(DATA_DIR)) mkdirSync(DATA_DIR, { recursive: true });
// ============================================================================
// Simple JSON File Backend (implements IMemoryBackend interface)
// ============================================================================
class JsonFileBackend {
constructor(filePath) {
this.filePath = filePath;
this.entries = new Map();
}
async initialize() {
if (existsSync(this.filePath)) {
try {
const data = JSON.parse(readFileSync(this.filePath, 'utf-8'));
if (Array.isArray(data)) {
for (const entry of data) this.entries.set(entry.id, entry);
}
} catch { /* start fresh */ }
}
}
async shutdown() { this._persist(); }
async store(entry) { this.entries.set(entry.id, entry); this._persist(); }
async get(id) { return this.entries.get(id) ?? null; }
async getByKey(key, ns) {
for (const e of this.entries.values()) {
if (e.key === key && (!ns || e.namespace === ns)) return e;
}
return null;
}
async update(id, updates) {
const e = this.entries.get(id);
if (!e) return null;
if (updates.metadata) Object.assign(e.metadata, updates.metadata);
if (updates.content !== undefined) e.content = updates.content;
if (updates.tags) e.tags = updates.tags;
e.updatedAt = Date.now();
this._persist();
return e;
}
async delete(id) { return this.entries.delete(id); }
async query(opts) {
let results = [...this.entries.values()];
if (opts?.namespace) results = results.filter(e => e.namespace === opts.namespace);
if (opts?.type) results = results.filter(e => e.type === opts.type);
if (opts?.limit) results = results.slice(0, opts.limit);
return results;
}
async search() { return []; } // No vector search in JSON backend
async bulkInsert(entries) { for (const e of entries) this.entries.set(e.id, e); this._persist(); }
async bulkDelete(ids) { let n = 0; for (const id of ids) { if (this.entries.delete(id)) n++; } this._persist(); return n; }
async count() { return this.entries.size; }
async listNamespaces() {
const ns = new Set();
for (const e of this.entries.values()) ns.add(e.namespace || 'default');
return [...ns];
}
async clearNamespace(ns) {
let n = 0;
for (const [id, e] of this.entries) {
if (e.namespace === ns) { this.entries.delete(id); n++; }
}
this._persist();
return n;
}
async getStats() {
return {
totalEntries: this.entries.size,
entriesByNamespace: {},
entriesByType: { semantic: 0, episodic: 0, procedural: 0, working: 0, cache: 0 },
memoryUsage: 0, avgQueryTime: 0, avgSearchTime: 0,
};
}
async healthCheck() {
return {
status: 'healthy',
components: {
storage: { status: 'healthy', latency: 0 },
index: { status: 'healthy', latency: 0 },
cache: { status: 'healthy', latency: 0 },
},
timestamp: Date.now(), issues: [], recommendations: [],
};
}
_persist() {
try {
writeFileSync(this.filePath, JSON.stringify([...this.entries.values()], null, 2), 'utf-8');
} catch { /* best effort */ }
}
}
// ============================================================================
// Resolve memory package path (local dev or npm installed)
// ============================================================================
async function loadMemoryPackage() {
// Strategy 1: Local dev (built dist)
const localDist = join(PROJECT_ROOT, 'v3/@claude-flow/memory/dist/index.js');
if (existsSync(localDist)) {
try {
return await import(`file://${localDist}`);
} catch { /* fall through */ }
}
// Strategy 2: npm installed @claude-flow/memory
try {
return await import('@claude-flow/memory');
} catch { /* fall through */ }
// Strategy 3: Installed via @claude-flow/cli which includes memory
const cliMemory = join(PROJECT_ROOT, 'node_modules/@claude-flow/memory/dist/index.js');
if (existsSync(cliMemory)) {
try {
return await import(`file://${cliMemory}`);
} catch { /* fall through */ }
}
return null;
}
// ============================================================================
// Read config from .claude-flow/config.yaml
// ============================================================================
function readConfig() {
const configPath = join(PROJECT_ROOT, '.claude-flow', 'config.yaml');
const defaults = {
learningBridge: { enabled: true, sonaMode: 'balanced', confidenceDecayRate: 0.005, accessBoostAmount: 0.03, consolidationThreshold: 10 },
memoryGraph: { enabled: true, pageRankDamping: 0.85, maxNodes: 5000, similarityThreshold: 0.8 },
agentScopes: { enabled: true, defaultScope: 'project' },
};
if (!existsSync(configPath)) return defaults;
try {
const yaml = readFileSync(configPath, 'utf-8');
// Simple YAML parser for the memory section
const getBool = (key) => {
const match = yaml.match(new RegExp(`${key}:\\s*(true|false)`, 'i'));
return match ? match[1] === 'true' : undefined;
};
const lbEnabled = getBool('learningBridge[\\s\\S]*?enabled');
if (lbEnabled !== undefined) defaults.learningBridge.enabled = lbEnabled;
const mgEnabled = getBool('memoryGraph[\\s\\S]*?enabled');
if (mgEnabled !== undefined) defaults.memoryGraph.enabled = mgEnabled;
const asEnabled = getBool('agentScopes[\\s\\S]*?enabled');
if (asEnabled !== undefined) defaults.agentScopes.enabled = asEnabled;
return defaults;
} catch {
return defaults;
}
}
// ============================================================================
// Commands
// ============================================================================
async function doImport() {
log('Importing auto memory files into bridge...');
const memPkg = await loadMemoryPackage();
if (!memPkg || !memPkg.AutoMemoryBridge) {
dim('Memory package not available — skipping auto memory import');
return;
}
const config = readConfig();
const backend = new JsonFileBackend(STORE_PATH);
await backend.initialize();
const bridgeConfig = {
workingDir: PROJECT_ROOT,
syncMode: 'on-session-end',
};
// Wire learning if enabled and available
if (config.learningBridge.enabled && memPkg.LearningBridge) {
bridgeConfig.learning = {
sonaMode: config.learningBridge.sonaMode,
confidenceDecayRate: config.learningBridge.confidenceDecayRate,
accessBoostAmount: config.learningBridge.accessBoostAmount,
consolidationThreshold: config.learningBridge.consolidationThreshold,
};
}
// Wire graph if enabled and available
if (config.memoryGraph.enabled && memPkg.MemoryGraph) {
bridgeConfig.graph = {
pageRankDamping: config.memoryGraph.pageRankDamping,
maxNodes: config.memoryGraph.maxNodes,
similarityThreshold: config.memoryGraph.similarityThreshold,
};
}
const bridge = new memPkg.AutoMemoryBridge(backend, bridgeConfig);
try {
const result = await bridge.importFromAutoMemory();
success(`Imported ${result.imported} entries (${result.skipped} skipped)`);
dim(`├─ Backend entries: ${await backend.count()}`);
dim(`├─ Learning: ${config.learningBridge.enabled ? 'active' : 'disabled'}`);
dim(`├─ Graph: ${config.memoryGraph.enabled ? 'active' : 'disabled'}`);
dim(`└─ Agent scopes: ${config.agentScopes.enabled ? 'active' : 'disabled'}`);
} catch (err) {
dim(`Import failed (non-critical): ${err.message}`);
}
await backend.shutdown();
}
async function doSync() {
log('Syncing insights to auto memory files...');
const memPkg = await loadMemoryPackage();
if (!memPkg || !memPkg.AutoMemoryBridge) {
dim('Memory package not available — skipping sync');
return;
}
const config = readConfig();
const backend = new JsonFileBackend(STORE_PATH);
await backend.initialize();
const entryCount = await backend.count();
if (entryCount === 0) {
dim('No entries to sync');
await backend.shutdown();
return;
}
const bridgeConfig = {
workingDir: PROJECT_ROOT,
syncMode: 'on-session-end',
};
if (config.learningBridge.enabled && memPkg.LearningBridge) {
bridgeConfig.learning = {
sonaMode: config.learningBridge.sonaMode,
confidenceDecayRate: config.learningBridge.confidenceDecayRate,
consolidationThreshold: config.learningBridge.consolidationThreshold,
};
}
if (config.memoryGraph.enabled && memPkg.MemoryGraph) {
bridgeConfig.graph = {
pageRankDamping: config.memoryGraph.pageRankDamping,
maxNodes: config.memoryGraph.maxNodes,
};
}
const bridge = new memPkg.AutoMemoryBridge(backend, bridgeConfig);
try {
const syncResult = await bridge.syncToAutoMemory();
success(`Synced ${syncResult.synced} entries to auto memory`);
dim(`├─ Categories updated: ${syncResult.categories?.join(', ') || 'none'}`);
dim(`└─ Backend entries: ${entryCount}`);
// Curate MEMORY.md index with graph-aware ordering
await bridge.curateIndex();
success('Curated MEMORY.md index');
} catch (err) {
dim(`Sync failed (non-critical): ${err.message}`);
}
if (bridge.destroy) bridge.destroy();
await backend.shutdown();
}
async function doStatus() {
const memPkg = await loadMemoryPackage();
const config = readConfig();
console.log('\n=== Auto Memory Bridge Status ===\n');
console.log(` Package: ${memPkg ? '✅ Available' : '❌ Not found'}`);
console.log(` Store: ${existsSync(STORE_PATH) ? '✅ ' + STORE_PATH : '⏸ Not initialized'}`);
console.log(` LearningBridge: ${config.learningBridge.enabled ? '✅ Enabled' : '⏸ Disabled'}`);
console.log(` MemoryGraph: ${config.memoryGraph.enabled ? '✅ Enabled' : '⏸ Disabled'}`);
console.log(` AgentScopes: ${config.agentScopes.enabled ? '✅ Enabled' : '⏸ Disabled'}`);
if (existsSync(STORE_PATH)) {
try {
const data = JSON.parse(readFileSync(STORE_PATH, 'utf-8'));
console.log(` Entries: ${Array.isArray(data) ? data.length : 0}`);
} catch { /* ignore */ }
}
console.log('');
}
// ============================================================================
// Main
// ============================================================================
const command = process.argv[2] || 'status';
try {
switch (command) {
case 'import': await doImport(); break;
case 'sync': await doSync(); break;
case 'status': await doStatus(); break;
default:
console.log('Usage: auto-memory-hook.mjs <import|sync|status>');
process.exit(1);
}
} catch (err) {
// Hooks must never crash Claude Code - fail silently
dim(`Error (non-critical): ${err.message}`);
}
+10 -10
View File
@@ -57,7 +57,7 @@ is_running() {
# Start the swarm monitor daemon
start_swarm_monitor() {
local interval="${1:-30}"
local interval="${1:-3}"
if is_running "$SWARM_MONITOR_PID"; then
log "Swarm monitor already running (PID: $(cat "$SWARM_MONITOR_PID"))"
@@ -78,7 +78,7 @@ start_swarm_monitor() {
# Start the metrics update daemon
start_metrics_daemon() {
local interval="${1:-60}" # Default 60 seconds - less frequent updates
local interval="${1:-30}" # Default 30 seconds for V3 sync
if is_running "$METRICS_DAEMON_PID"; then
log "Metrics daemon already running (PID: $(cat "$METRICS_DAEMON_PID"))"
@@ -126,8 +126,8 @@ stop_daemon() {
# Start all daemons
start_all() {
log "Starting all Claude Flow daemons..."
start_swarm_monitor "${1:-30}"
start_metrics_daemon "${2:-60}"
start_swarm_monitor "${1:-3}"
start_metrics_daemon "${2:-5}"
# Initial metrics update
"$SCRIPT_DIR/swarm-monitor.sh" check > /dev/null 2>&1
@@ -207,22 +207,22 @@ show_status() {
# Main command handling
case "${1:-status}" in
"start")
start_all "${2:-30}" "${3:-60}"
start_all "${2:-3}" "${3:-5}"
;;
"stop")
stop_all
;;
"restart")
restart_all "${2:-30}" "${3:-60}"
restart_all "${2:-3}" "${3:-5}"
;;
"status")
show_status
;;
"start-swarm")
start_swarm_monitor "${2:-30}"
start_swarm_monitor "${2:-3}"
;;
"start-metrics")
start_metrics_daemon "${2:-60}"
start_metrics_daemon "${2:-5}"
;;
"help"|"-h"|"--help")
echo "Claude Flow V3 Daemon Manager"
@@ -239,8 +239,8 @@ case "${1:-status}" in
echo " help Show this help"
echo ""
echo "Examples:"
echo " $0 start # Start with defaults (30s swarm, 60s metrics)"
echo " $0 start 10 30 # Start with 10s swarm, 30s metrics intervals"
echo " $0 start # Start with defaults (3s swarm, 5s metrics)"
echo " $0 start 2 3 # Start with 2s swarm, 3s metrics intervals"
echo " $0 status # Show current status"
echo " $0 stop # Stop all daemons"
;;
-232
View File
@@ -1,232 +0,0 @@
#!/usr/bin/env node
/**
* Claude Flow Hook Handler (Cross-Platform)
* Dispatches hook events to the appropriate helper modules.
*
* Usage: node hook-handler.cjs <command> [args...]
*
* Commands:
* route - Route a task to optimal agent (reads PROMPT from env/stdin)
* pre-bash - Validate command safety before execution
* post-edit - Record edit outcome for learning
* session-restore - Restore previous session state
* session-end - End session and persist state
*/
const path = require('path');
const fs = require('fs');
const helpersDir = __dirname;
// Safe require with stdout suppression - the helper modules have CLI
// sections that run unconditionally on require(), so we mute console
// during the require to prevent noisy output.
function safeRequire(modulePath) {
try {
if (fs.existsSync(modulePath)) {
const origLog = console.log;
const origError = console.error;
console.log = () => {};
console.error = () => {};
try {
const mod = require(modulePath);
return mod;
} finally {
console.log = origLog;
console.error = origError;
}
}
} catch (e) {
// silently fail
}
return null;
}
const router = safeRequire(path.join(helpersDir, 'router.js'));
const session = safeRequire(path.join(helpersDir, 'session.js'));
const memory = safeRequire(path.join(helpersDir, 'memory.js'));
const intelligence = safeRequire(path.join(helpersDir, 'intelligence.cjs'));
// Get the command from argv
const [,, command, ...args] = process.argv;
// Get prompt from environment variable (set by Claude Code hooks)
const prompt = process.env.PROMPT || process.env.TOOL_INPUT_command || args.join(' ') || '';
const handlers = {
'route': () => {
// Inject ranked intelligence context before routing
if (intelligence && intelligence.getContext) {
try {
const ctx = intelligence.getContext(prompt);
if (ctx) console.log(ctx);
} catch (e) { /* non-fatal */ }
}
if (router && router.routeTask) {
const result = router.routeTask(prompt);
// Format output for Claude Code hook consumption
const output = [
`[INFO] Routing task: ${prompt.substring(0, 80) || '(no prompt)'}`,
'',
'Routing Method',
' - Method: keyword',
' - Backend: keyword matching',
` - Latency: ${(Math.random() * 0.5 + 0.1).toFixed(3)}ms`,
' - Matched Pattern: keyword-fallback',
'',
'Semantic Matches:',
' bugfix-task: 15.0%',
' devops-task: 14.0%',
' testing-task: 13.0%',
'',
'+------------------- Primary Recommendation -------------------+',
`| Agent: ${result.agent.padEnd(53)}|`,
`| Confidence: ${(result.confidence * 100).toFixed(1)}%${' '.repeat(44)}|`,
`| Reason: ${result.reason.substring(0, 53).padEnd(53)}|`,
'+--------------------------------------------------------------+',
'',
'Alternative Agents',
'+------------+------------+-------------------------------------+',
'| Agent Type | Confidence | Reason |',
'+------------+------------+-------------------------------------+',
'| researcher | 60.0% | Alternative agent for researcher... |',
'| tester | 50.0% | Alternative agent for tester cap... |',
'+------------+------------+-------------------------------------+',
'',
'Estimated Metrics',
' - Success Probability: 70.0%',
' - Estimated Duration: 10-30 min',
' - Complexity: LOW',
];
console.log(output.join('\n'));
} else {
console.log('[INFO] Router not available, using default routing');
}
},
'pre-bash': () => {
// Basic command safety check
const cmd = prompt.toLowerCase();
const dangerous = ['rm -rf /', 'format c:', 'del /s /q c:\\', ':(){:|:&};:'];
for (const d of dangerous) {
if (cmd.includes(d)) {
console.error(`[BLOCKED] Dangerous command detected: ${d}`);
process.exit(1);
}
}
console.log('[OK] Command validated');
},
'post-edit': () => {
// Record edit for session metrics
if (session && session.metric) {
try { session.metric('edits'); } catch (e) { /* no active session */ }
}
// Record edit for intelligence consolidation
if (intelligence && intelligence.recordEdit) {
try {
const file = process.env.TOOL_INPUT_file_path || args[0] || '';
intelligence.recordEdit(file);
} catch (e) { /* non-fatal */ }
}
console.log('[OK] Edit recorded');
},
'session-restore': () => {
if (session) {
// Try restore first, fall back to start
const existing = session.restore && session.restore();
if (!existing) {
session.start && session.start();
}
} else {
// Minimal session restore output
const sessionId = `session-${Date.now()}`;
console.log(`[INFO] Restoring session: %SESSION_ID%`);
console.log('');
console.log(`[OK] Session restored from %SESSION_ID%`);
console.log(`New session ID: ${sessionId}`);
console.log('');
console.log('Restored State');
console.log('+----------------+-------+');
console.log('| Item | Count |');
console.log('+----------------+-------+');
console.log('| Tasks | 0 |');
console.log('| Agents | 0 |');
console.log('| Memory Entries | 0 |');
console.log('+----------------+-------+');
}
// Initialize intelligence graph after session restore
if (intelligence && intelligence.init) {
try {
const result = intelligence.init();
if (result && result.nodes > 0) {
console.log(`[INTELLIGENCE] Loaded ${result.nodes} patterns, ${result.edges} edges`);
}
} catch (e) { /* non-fatal */ }
}
},
'session-end': () => {
// Consolidate intelligence before ending session
if (intelligence && intelligence.consolidate) {
try {
const result = intelligence.consolidate();
if (result && result.entries > 0) {
console.log(`[INTELLIGENCE] Consolidated: ${result.entries} entries, ${result.edges} edges${result.newEntries > 0 ? `, ${result.newEntries} new` : ''}, PageRank recomputed`);
}
} catch (e) { /* non-fatal */ }
}
if (session && session.end) {
session.end();
} else {
console.log('[OK] Session ended');
}
},
'pre-task': () => {
if (session && session.metric) {
try { session.metric('tasks'); } catch (e) { /* no active session */ }
}
// Route the task if router is available
if (router && router.routeTask && prompt) {
const result = router.routeTask(prompt);
console.log(`[INFO] Task routed to: ${result.agent} (confidence: ${result.confidence})`);
} else {
console.log('[OK] Task started');
}
},
'post-task': () => {
// Implicit success feedback for intelligence
if (intelligence && intelligence.feedback) {
try {
intelligence.feedback(true);
} catch (e) { /* non-fatal */ }
}
console.log('[OK] Task completed');
},
'stats': () => {
if (intelligence && intelligence.stats) {
intelligence.stats(args.includes('--json'));
} else {
console.log('[WARN] Intelligence module not available. Run session-restore first.');
}
},
};
// Execute the handler
if (command && handlers[command]) {
try {
handlers[command]();
} catch (e) {
// Hooks should never crash Claude Code - fail silently
console.log(`[WARN] Hook ${command} encountered an error: ${e.message}`);
}
} else if (command) {
// Unknown command - pass through without error
console.log(`[OK] Hook: ${command}`);
} else {
console.log('Usage: hook-handler.cjs <route|pre-bash|post-edit|session-restore|session-end|pre-task|post-task|stats>');
}
-928
View File
@@ -1,928 +0,0 @@
#!/usr/bin/env node
/**
* Intelligence Layer (ADR-050)
*
* Closes the intelligence loop by wiring PageRank-ranked memory into
* the hook system. Pure CJS — no ESM imports of @claude-flow/memory.
*
* Data files (all under .claude-flow/data/):
* auto-memory-store.json — written by auto-memory-hook.mjs
* graph-state.json — serialized graph (nodes + edges + pageRanks)
* ranked-context.json — pre-computed ranked entries for fast lookup
* pending-insights.jsonl — append-only edit/task log
*/
'use strict';
const fs = require('fs');
const path = require('path');
const DATA_DIR = path.join(process.cwd(), '.claude-flow', 'data');
const STORE_PATH = path.join(DATA_DIR, 'auto-memory-store.json');
const GRAPH_PATH = path.join(DATA_DIR, 'graph-state.json');
const RANKED_PATH = path.join(DATA_DIR, 'ranked-context.json');
const PENDING_PATH = path.join(DATA_DIR, 'pending-insights.jsonl');
const SESSION_DIR = path.join(process.cwd(), '.claude-flow', 'sessions');
const SESSION_FILE = path.join(SESSION_DIR, 'current.json');
// ── Stop words for trigram matching ──────────────────────────────────────────
const STOP_WORDS = new Set([
'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
'should', 'may', 'might', 'shall', 'can', 'to', 'of', 'in', 'for',
'on', 'with', 'at', 'by', 'from', 'as', 'into', 'through', 'during',
'before', 'after', 'and', 'but', 'or', 'nor', 'not', 'so', 'yet',
'both', 'either', 'neither', 'each', 'every', 'all', 'any', 'few',
'more', 'most', 'other', 'some', 'such', 'no', 'only', 'own', 'same',
'than', 'too', 'very', 'just', 'because', 'if', 'when', 'which',
'who', 'whom', 'this', 'that', 'these', 'those', 'it', 'its',
]);
// ── Helpers ──────────────────────────────────────────────────────────────────
function ensureDataDir() {
if (!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR, { recursive: true });
}
function readJSON(filePath) {
try {
if (fs.existsSync(filePath)) return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
} catch { /* corrupt file — start fresh */ }
return null;
}
function writeJSON(filePath, data) {
ensureDataDir();
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');
}
function tokenize(text) {
if (!text) return [];
return text.toLowerCase()
.replace(/[^a-z0-9\s-]/g, ' ')
.split(/\s+/)
.filter(w => w.length > 2 && !STOP_WORDS.has(w));
}
function trigrams(words) {
const t = new Set();
for (const w of words) {
for (let i = 0; i <= w.length - 3; i++) t.add(w.slice(i, i + 3));
}
return t;
}
function jaccardSimilarity(setA, setB) {
if (setA.size === 0 && setB.size === 0) return 0;
let intersection = 0;
for (const item of setA) { if (setB.has(item)) intersection++; }
return intersection / (setA.size + setB.size - intersection);
}
// ── Session state helpers ────────────────────────────────────────────────────
function sessionGet(key) {
try {
if (!fs.existsSync(SESSION_FILE)) return null;
const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
return key ? (session.context || {})[key] : session.context;
} catch { return null; }
}
function sessionSet(key, value) {
try {
if (!fs.existsSync(SESSION_DIR)) fs.mkdirSync(SESSION_DIR, { recursive: true });
let session = {};
if (fs.existsSync(SESSION_FILE)) {
session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
}
if (!session.context) session.context = {};
session.context[key] = value;
session.updatedAt = new Date().toISOString();
fs.writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2), 'utf-8');
} catch { /* best effort */ }
}
// ── PageRank ─────────────────────────────────────────────────────────────────
function computePageRank(nodes, edges, damping, maxIter) {
damping = damping || 0.85;
maxIter = maxIter || 30;
const ids = Object.keys(nodes);
const n = ids.length;
if (n === 0) return {};
// Build adjacency: outgoing edges per node
const outLinks = {};
const inLinks = {};
for (const id of ids) { outLinks[id] = []; inLinks[id] = []; }
for (const edge of edges) {
if (outLinks[edge.sourceId]) outLinks[edge.sourceId].push(edge.targetId);
if (inLinks[edge.targetId]) inLinks[edge.targetId].push(edge.sourceId);
}
// Initialize ranks
const ranks = {};
for (const id of ids) ranks[id] = 1 / n;
// Power iteration (with dangling node redistribution)
for (let iter = 0; iter < maxIter; iter++) {
const newRanks = {};
let diff = 0;
// Collect rank from dangling nodes (no outgoing edges)
let danglingSum = 0;
for (const id of ids) {
if (outLinks[id].length === 0) danglingSum += ranks[id];
}
for (const id of ids) {
let sum = 0;
for (const src of inLinks[id]) {
const outCount = outLinks[src].length;
if (outCount > 0) sum += ranks[src] / outCount;
}
// Dangling rank distributed evenly + teleport
newRanks[id] = (1 - damping) / n + damping * (sum + danglingSum / n);
diff += Math.abs(newRanks[id] - ranks[id]);
}
for (const id of ids) ranks[id] = newRanks[id];
if (diff < 1e-6) break; // converged
}
return ranks;
}
// ── Edge building ────────────────────────────────────────────────────────────
function buildEdges(entries) {
const edges = [];
const byCategory = {};
for (const entry of entries) {
const cat = entry.category || entry.namespace || 'default';
if (!byCategory[cat]) byCategory[cat] = [];
byCategory[cat].push(entry);
}
// Temporal edges: entries from same sourceFile
const byFile = {};
for (const entry of entries) {
const file = (entry.metadata && entry.metadata.sourceFile) || null;
if (file) {
if (!byFile[file]) byFile[file] = [];
byFile[file].push(entry);
}
}
for (const file of Object.keys(byFile)) {
const group = byFile[file];
for (let i = 0; i < group.length - 1; i++) {
edges.push({
sourceId: group[i].id,
targetId: group[i + 1].id,
type: 'temporal',
weight: 0.5,
});
}
}
// Similarity edges within categories (Jaccard > 0.3)
for (const cat of Object.keys(byCategory)) {
const group = byCategory[cat];
for (let i = 0; i < group.length; i++) {
const triA = trigrams(tokenize(group[i].content || group[i].summary || ''));
for (let j = i + 1; j < group.length; j++) {
const triB = trigrams(tokenize(group[j].content || group[j].summary || ''));
const sim = jaccardSimilarity(triA, triB);
if (sim > 0.3) {
edges.push({
sourceId: group[i].id,
targetId: group[j].id,
type: 'similar',
weight: sim,
});
}
}
}
}
return edges;
}
// ── Bootstrap from MEMORY.md files ───────────────────────────────────────────
/**
* If auto-memory-store.json is empty, bootstrap by parsing MEMORY.md and
* topic files from the auto-memory directory. This removes the dependency
* on @claude-flow/memory for the initial seed.
*/
function bootstrapFromMemoryFiles() {
const entries = [];
const cwd = process.cwd();
// Search for auto-memory directories
const candidates = [
// Claude Code auto-memory (project-scoped)
path.join(require('os').homedir(), '.claude', 'projects'),
// Local project memory
path.join(cwd, '.claude-flow', 'memory'),
path.join(cwd, '.claude', 'memory'),
];
// Find MEMORY.md in project-scoped dirs
for (const base of candidates) {
if (!fs.existsSync(base)) continue;
// For the projects dir, scan subdirectories for memory/
if (base.endsWith('projects')) {
try {
const projectDirs = fs.readdirSync(base);
for (const pdir of projectDirs) {
const memDir = path.join(base, pdir, 'memory');
if (fs.existsSync(memDir)) {
parseMemoryDir(memDir, entries);
}
}
} catch { /* skip */ }
} else if (fs.existsSync(base)) {
parseMemoryDir(base, entries);
}
}
return entries;
}
function parseMemoryDir(dir, entries) {
try {
const files = fs.readdirSync(dir).filter(f => f.endsWith('.md'));
for (const file of files) {
// Validate file name to prevent path traversal
if (file.includes('..') || file.includes('/') || file.includes('\\')) {
continue;
}
const filePath = path.join(dir, file);
// Additional validation: ensure resolved path is within the base directory
const resolvedPath = path.resolve(filePath);
const resolvedDir = path.resolve(dir);
if (!resolvedPath.startsWith(resolvedDir)) {
continue; // Path traversal attempt detected
}
const content = fs.readFileSync(filePath, 'utf-8');
if (!content.trim()) continue;
// Parse markdown sections as separate entries
const sections = content.split(/^##?\s+/m).filter(Boolean);
for (const section of sections) {
const lines = section.trim().split('\n');
const title = lines[0].trim();
const body = lines.slice(1).join('\n').trim();
if (!body || body.length < 10) continue;
const id = `mem-${file.replace('.md', '')}-${title.replace(/[^a-z0-9]/gi, '-').toLowerCase().slice(0, 30)}`;
entries.push({
id,
key: title.toLowerCase().replace(/[^a-z0-9]+/g, '-').slice(0, 50),
content: body.slice(0, 500),
summary: title,
namespace: file === 'MEMORY.md' ? 'core' : file.replace('.md', ''),
type: 'semantic',
metadata: { sourceFile: filePath, bootstrapped: true },
createdAt: Date.now(),
});
}
}
} catch { /* skip unreadable dirs */ }
}
// ── Exported functions ───────────────────────────────────────────────────────
/**
* init() — Called from session-restore. Budget: <200ms.
* Reads auto-memory-store.json, builds graph, computes PageRank, writes caches.
* If store is empty, bootstraps from MEMORY.md files directly.
*/
function init() {
ensureDataDir();
// Check if graph-state.json is fresh (within 60s of store)
const graphState = readJSON(GRAPH_PATH);
let store = readJSON(STORE_PATH);
// Bootstrap from MEMORY.md files if store is empty
if (!store || !Array.isArray(store) || store.length === 0) {
const bootstrapped = bootstrapFromMemoryFiles();
if (bootstrapped.length > 0) {
store = bootstrapped;
writeJSON(STORE_PATH, store);
} else {
return { nodes: 0, edges: 0, message: 'No memory entries to index' };
}
}
// Skip rebuild if graph is fresh and store hasn't changed
if (graphState && graphState.nodeCount === store.length) {
const age = Date.now() - (graphState.updatedAt || 0);
if (age < 60000) {
return {
nodes: graphState.nodeCount || Object.keys(graphState.nodes || {}).length,
edges: (graphState.edges || []).length,
message: 'Graph cache hit',
};
}
}
// Build nodes
const nodes = {};
for (const entry of store) {
const id = entry.id || entry.key || `entry-${Math.random().toString(36).slice(2, 8)}`;
nodes[id] = {
id,
category: entry.namespace || entry.type || 'default',
confidence: (entry.metadata && entry.metadata.confidence) || 0.5,
accessCount: (entry.metadata && entry.metadata.accessCount) || 0,
createdAt: entry.createdAt || Date.now(),
};
// Ensure entry has id for edge building
entry.id = id;
}
// Build edges
const edges = buildEdges(store);
// Compute PageRank
const pageRanks = computePageRank(nodes, edges, 0.85, 30);
// Write graph state
const graph = {
version: 1,
updatedAt: Date.now(),
nodeCount: Object.keys(nodes).length,
nodes,
edges,
pageRanks,
};
writeJSON(GRAPH_PATH, graph);
// Build ranked context for fast lookup
const rankedEntries = store.map(entry => {
const id = entry.id;
const content = entry.content || entry.value || '';
const summary = entry.summary || entry.key || '';
const words = tokenize(content + ' ' + summary);
return {
id,
content,
summary,
category: entry.namespace || entry.type || 'default',
confidence: nodes[id] ? nodes[id].confidence : 0.5,
pageRank: pageRanks[id] || 0,
accessCount: nodes[id] ? nodes[id].accessCount : 0,
words,
};
}).sort((a, b) => {
const scoreA = 0.6 * a.pageRank + 0.4 * a.confidence;
const scoreB = 0.6 * b.pageRank + 0.4 * b.confidence;
return scoreB - scoreA;
});
const ranked = {
version: 1,
computedAt: Date.now(),
entries: rankedEntries,
};
writeJSON(RANKED_PATH, ranked);
return {
nodes: Object.keys(nodes).length,
edges: edges.length,
message: 'Graph built and ranked',
};
}
/**
* getContext(prompt) — Called from route. Budget: <15ms.
* Matches prompt to ranked entries, returns top-5 formatted context.
*/
function getContext(prompt) {
if (!prompt) return null;
const ranked = readJSON(RANKED_PATH);
if (!ranked || !ranked.entries || ranked.entries.length === 0) return null;
const promptWords = tokenize(prompt);
if (promptWords.length === 0) return null;
const promptTrigrams = trigrams(promptWords);
const ALPHA = 0.6; // content match weight
const MIN_THRESHOLD = 0.05;
const TOP_K = 5;
// Score each entry
const scored = [];
for (const entry of ranked.entries) {
const entryTrigrams = trigrams(entry.words || []);
const contentMatch = jaccardSimilarity(promptTrigrams, entryTrigrams);
const score = ALPHA * contentMatch + (1 - ALPHA) * (entry.pageRank || 0);
if (score >= MIN_THRESHOLD) {
scored.push({ ...entry, score });
}
}
if (scored.length === 0) return null;
// Sort by score descending, take top-K
scored.sort((a, b) => b.score - a.score);
const topEntries = scored.slice(0, TOP_K);
// Boost previously matched patterns (implicit success: user continued working)
const prevMatched = sessionGet('lastMatchedPatterns');
// Store NEW matched IDs in session state for feedback
const matchedIds = topEntries.map(e => e.id);
sessionSet('lastMatchedPatterns', matchedIds);
// Only boost previous if they differ from current (avoid double-boosting)
if (prevMatched && Array.isArray(prevMatched)) {
const newSet = new Set(matchedIds);
const toBoost = prevMatched.filter(id => !newSet.has(id));
if (toBoost.length > 0) boostConfidence(toBoost, 0.03);
}
// Format output
const lines = ['[INTELLIGENCE] Relevant patterns for this task:'];
for (let i = 0; i < topEntries.length; i++) {
const e = topEntries[i];
const display = (e.summary || e.content || '').slice(0, 80);
const accessed = e.accessCount || 0;
lines.push(` * (${e.score.toFixed(2)}) ${display} [rank #${i + 1}, ${accessed}x accessed]`);
}
return lines.join('\n');
}
/**
* recordEdit(file) — Called from post-edit. Budget: <2ms.
* Appends to pending-insights.jsonl.
*/
function recordEdit(file) {
ensureDataDir();
const entry = JSON.stringify({
type: 'edit',
file: file || 'unknown',
timestamp: Date.now(),
sessionId: sessionGet('sessionId') || null,
});
fs.appendFileSync(PENDING_PATH, entry + '\n', 'utf-8');
}
/**
* feedback(success) — Called from post-task. Budget: <10ms.
* Boosts or decays confidence for last-matched patterns.
*/
function feedback(success) {
const matchedIds = sessionGet('lastMatchedPatterns');
if (!matchedIds || !Array.isArray(matchedIds)) return;
const amount = success ? 0.05 : -0.02;
boostConfidence(matchedIds, amount);
}
function boostConfidence(ids, amount) {
const ranked = readJSON(RANKED_PATH);
if (!ranked || !ranked.entries) return;
let changed = false;
for (const entry of ranked.entries) {
if (ids.includes(entry.id)) {
entry.confidence = Math.max(0, Math.min(1, (entry.confidence || 0.5) + amount));
entry.accessCount = (entry.accessCount || 0) + 1;
changed = true;
}
}
if (changed) writeJSON(RANKED_PATH, ranked);
// Also update graph-state confidence
const graph = readJSON(GRAPH_PATH);
if (graph && graph.nodes) {
for (const id of ids) {
if (graph.nodes[id]) {
graph.nodes[id].confidence = Math.max(0, Math.min(1, (graph.nodes[id].confidence || 0.5) + amount));
graph.nodes[id].accessCount = (graph.nodes[id].accessCount || 0) + 1;
}
}
writeJSON(GRAPH_PATH, graph);
}
}
/**
* consolidate() — Called from session-end. Budget: <500ms.
* Processes pending insights, rebuilds edges, recomputes PageRank.
*/
function consolidate() {
ensureDataDir();
const store = readJSON(STORE_PATH);
if (!store || !Array.isArray(store)) {
return { entries: 0, edges: 0, newEntries: 0, message: 'No store to consolidate' };
}
// 1. Process pending insights
let newEntries = 0;
if (fs.existsSync(PENDING_PATH)) {
const lines = fs.readFileSync(PENDING_PATH, 'utf-8').trim().split('\n').filter(Boolean);
const editCounts = {};
for (const line of lines) {
try {
const insight = JSON.parse(line);
if (insight.file) {
editCounts[insight.file] = (editCounts[insight.file] || 0) + 1;
}
} catch { /* skip malformed */ }
}
// Create entries for frequently-edited files (3+ edits)
for (const [file, count] of Object.entries(editCounts)) {
if (count >= 3) {
const exists = store.some(e =>
(e.metadata && e.metadata.sourceFile === file && e.metadata.autoGenerated)
);
if (!exists) {
store.push({
id: `insight-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
key: `frequent-edit-${path.basename(file)}`,
content: `File ${file} was edited ${count} times this session — likely a hot path worth monitoring.`,
summary: `Frequently edited: ${path.basename(file)} (${count}x)`,
namespace: 'insights',
type: 'procedural',
metadata: { sourceFile: file, editCount: count, autoGenerated: true },
createdAt: Date.now(),
});
newEntries++;
}
}
}
// Clear pending
fs.writeFileSync(PENDING_PATH, '', 'utf-8');
}
// 2. Confidence decay for unaccessed entries
const graph = readJSON(GRAPH_PATH);
if (graph && graph.nodes) {
const now = Date.now();
for (const id of Object.keys(graph.nodes)) {
const node = graph.nodes[id];
const hoursSinceCreation = (now - (node.createdAt || now)) / (1000 * 60 * 60);
if (node.accessCount === 0 && hoursSinceCreation > 24) {
node.confidence = Math.max(0.05, (node.confidence || 0.5) - 0.005 * Math.floor(hoursSinceCreation / 24));
}
}
}
// 3. Rebuild edges with updated store
for (const entry of store) {
if (!entry.id) entry.id = `entry-${Math.random().toString(36).slice(2, 8)}`;
}
const edges = buildEdges(store);
// 4. Build updated nodes
const nodes = {};
for (const entry of store) {
nodes[entry.id] = {
id: entry.id,
category: entry.namespace || entry.type || 'default',
confidence: (graph && graph.nodes && graph.nodes[entry.id])
? graph.nodes[entry.id].confidence
: (entry.metadata && entry.metadata.confidence) || 0.5,
accessCount: (graph && graph.nodes && graph.nodes[entry.id])
? graph.nodes[entry.id].accessCount
: (entry.metadata && entry.metadata.accessCount) || 0,
createdAt: entry.createdAt || Date.now(),
};
}
// 5. Recompute PageRank
const pageRanks = computePageRank(nodes, edges, 0.85, 30);
// 6. Write updated graph
writeJSON(GRAPH_PATH, {
version: 1,
updatedAt: Date.now(),
nodeCount: Object.keys(nodes).length,
nodes,
edges,
pageRanks,
});
// 7. Write updated ranked context
const rankedEntries = store.map(entry => {
const id = entry.id;
const content = entry.content || entry.value || '';
const summary = entry.summary || entry.key || '';
const words = tokenize(content + ' ' + summary);
return {
id,
content,
summary,
category: entry.namespace || entry.type || 'default',
confidence: nodes[id] ? nodes[id].confidence : 0.5,
pageRank: pageRanks[id] || 0,
accessCount: nodes[id] ? nodes[id].accessCount : 0,
words,
};
}).sort((a, b) => {
const scoreA = 0.6 * a.pageRank + 0.4 * a.confidence;
const scoreB = 0.6 * b.pageRank + 0.4 * b.confidence;
return scoreB - scoreA;
});
writeJSON(RANKED_PATH, {
version: 1,
computedAt: Date.now(),
entries: rankedEntries,
});
// 8. Persist updated store (with new insight entries)
if (newEntries > 0) writeJSON(STORE_PATH, store);
// 9. Save snapshot for delta tracking
const updatedGraph = readJSON(GRAPH_PATH);
const updatedRanked = readJSON(RANKED_PATH);
saveSnapshot(updatedGraph, updatedRanked);
return {
entries: store.length,
edges: edges.length,
newEntries,
message: 'Consolidated',
};
}
// ── Snapshot for delta tracking ─────────────────────────────────────────────
const SNAPSHOT_PATH = path.join(DATA_DIR, 'intelligence-snapshot.json');
function saveSnapshot(graph, ranked) {
const snap = {
timestamp: Date.now(),
nodes: graph ? Object.keys(graph.nodes || {}).length : 0,
edges: graph ? (graph.edges || []).length : 0,
pageRankSum: 0,
confidences: [],
accessCounts: [],
topPatterns: [],
};
if (graph && graph.pageRanks) {
for (const v of Object.values(graph.pageRanks)) snap.pageRankSum += v;
}
if (graph && graph.nodes) {
for (const n of Object.values(graph.nodes)) {
snap.confidences.push(n.confidence || 0.5);
snap.accessCounts.push(n.accessCount || 0);
}
}
if (ranked && ranked.entries) {
snap.topPatterns = ranked.entries.slice(0, 10).map(e => ({
id: e.id,
summary: (e.summary || '').slice(0, 60),
confidence: e.confidence || 0.5,
pageRank: e.pageRank || 0,
accessCount: e.accessCount || 0,
}));
}
// Keep history: append to array, cap at 50
let history = readJSON(SNAPSHOT_PATH);
if (!Array.isArray(history)) history = [];
history.push(snap);
if (history.length > 50) history = history.slice(-50);
writeJSON(SNAPSHOT_PATH, history);
}
/**
* stats() — Diagnostic report showing intelligence health and improvement.
* Can be called as: node intelligence.cjs stats [--json]
*/
function stats(outputJson) {
const graph = readJSON(GRAPH_PATH);
const ranked = readJSON(RANKED_PATH);
const history = readJSON(SNAPSHOT_PATH) || [];
const pending = fs.existsSync(PENDING_PATH)
? fs.readFileSync(PENDING_PATH, 'utf-8').trim().split('\n').filter(Boolean).length
: 0;
// Current state
const nodes = graph ? Object.keys(graph.nodes || {}).length : 0;
const edges = graph ? (graph.edges || []).length : 0;
const density = nodes > 1 ? (2 * edges) / (nodes * (nodes - 1)) : 0;
// Confidence distribution
const confidences = [];
const accessCounts = [];
if (graph && graph.nodes) {
for (const n of Object.values(graph.nodes)) {
confidences.push(n.confidence || 0.5);
accessCounts.push(n.accessCount || 0);
}
}
confidences.sort((a, b) => a - b);
const confMin = confidences.length ? confidences[0] : 0;
const confMax = confidences.length ? confidences[confidences.length - 1] : 0;
const confMean = confidences.length ? confidences.reduce((s, c) => s + c, 0) / confidences.length : 0;
const confMedian = confidences.length ? confidences[Math.floor(confidences.length / 2)] : 0;
// Access stats
const totalAccess = accessCounts.reduce((s, c) => s + c, 0);
const accessedCount = accessCounts.filter(c => c > 0).length;
// PageRank stats
let prSum = 0, prMax = 0, prMaxId = '';
if (graph && graph.pageRanks) {
for (const [id, pr] of Object.entries(graph.pageRanks)) {
prSum += pr;
if (pr > prMax) { prMax = pr; prMaxId = id; }
}
}
// Top patterns by composite score
const topPatterns = (ranked && ranked.entries || []).slice(0, 10).map((e, i) => ({
rank: i + 1,
summary: (e.summary || '').slice(0, 60),
confidence: (e.confidence || 0.5).toFixed(3),
pageRank: (e.pageRank || 0).toFixed(4),
accessed: e.accessCount || 0,
score: (0.6 * (e.pageRank || 0) + 0.4 * (e.confidence || 0.5)).toFixed(4),
}));
// Edge type breakdown
const edgeTypes = {};
if (graph && graph.edges) {
for (const e of graph.edges) {
edgeTypes[e.type || 'unknown'] = (edgeTypes[e.type || 'unknown'] || 0) + 1;
}
}
// Delta from previous snapshot
let delta = null;
if (history.length >= 2) {
const prev = history[history.length - 2];
const curr = history[history.length - 1];
const elapsed = (curr.timestamp - prev.timestamp) / 1000;
const prevConfMean = prev.confidences.length
? prev.confidences.reduce((s, c) => s + c, 0) / prev.confidences.length : 0;
const currConfMean = curr.confidences.length
? curr.confidences.reduce((s, c) => s + c, 0) / curr.confidences.length : 0;
const prevAccess = prev.accessCounts.reduce((s, c) => s + c, 0);
const currAccess = curr.accessCounts.reduce((s, c) => s + c, 0);
delta = {
elapsed: elapsed < 3600 ? `${Math.round(elapsed / 60)}m` : `${(elapsed / 3600).toFixed(1)}h`,
nodes: curr.nodes - prev.nodes,
edges: curr.edges - prev.edges,
confidenceMean: currConfMean - prevConfMean,
totalAccess: currAccess - prevAccess,
};
}
// Trend over all history
let trend = null;
if (history.length >= 3) {
const first = history[0];
const last = history[history.length - 1];
const sessions = history.length;
const firstConfMean = first.confidences.length
? first.confidences.reduce((s, c) => s + c, 0) / first.confidences.length : 0;
const lastConfMean = last.confidences.length
? last.confidences.reduce((s, c) => s + c, 0) / last.confidences.length : 0;
trend = {
sessions,
nodeGrowth: last.nodes - first.nodes,
edgeGrowth: last.edges - first.edges,
confidenceDrift: lastConfMean - firstConfMean,
direction: lastConfMean > firstConfMean ? 'improving' :
lastConfMean < firstConfMean ? 'declining' : 'stable',
};
}
const report = {
graph: { nodes, edges, density: +density.toFixed(4) },
confidence: {
min: +confMin.toFixed(3), max: +confMax.toFixed(3),
mean: +confMean.toFixed(3), median: +confMedian.toFixed(3),
},
access: { total: totalAccess, patternsAccessed: accessedCount, patternsNeverAccessed: nodes - accessedCount },
pageRank: { sum: +prSum.toFixed(4), topNode: prMaxId, topNodeRank: +prMax.toFixed(4) },
edgeTypes,
pendingInsights: pending,
snapshots: history.length,
topPatterns,
delta,
trend,
};
if (outputJson) {
console.log(JSON.stringify(report, null, 2));
return report;
}
// Human-readable output
const bar = '+' + '-'.repeat(62) + '+';
console.log(bar);
console.log('|' + ' Intelligence Diagnostics (ADR-050)'.padEnd(62) + '|');
console.log(bar);
console.log('');
console.log(' Graph');
console.log(` Nodes: ${nodes}`);
console.log(` Edges: ${edges} (${Object.entries(edgeTypes).map(([t,c]) => `${c} ${t}`).join(', ') || 'none'})`);
console.log(` Density: ${(density * 100).toFixed(1)}%`);
console.log('');
console.log(' Confidence');
console.log(` Min: ${confMin.toFixed(3)}`);
console.log(` Max: ${confMax.toFixed(3)}`);
console.log(` Mean: ${confMean.toFixed(3)}`);
console.log(` Median: ${confMedian.toFixed(3)}`);
console.log('');
console.log(' Access');
console.log(` Total accesses: ${totalAccess}`);
console.log(` Patterns used: ${accessedCount}/${nodes}`);
console.log(` Never accessed: ${nodes - accessedCount}`);
console.log(` Pending insights: ${pending}`);
console.log('');
console.log(' PageRank');
console.log(` Sum: ${prSum.toFixed(4)} (should be ~1.0)`);
console.log(` Top node: ${prMaxId || '(none)'} (${prMax.toFixed(4)})`);
console.log('');
if (topPatterns.length > 0) {
console.log(' Top Patterns (by composite score)');
console.log(' ' + '-'.repeat(60));
for (const p of topPatterns) {
console.log(` #${p.rank} ${p.summary}`);
console.log(` conf=${p.confidence} pr=${p.pageRank} score=${p.score} accessed=${p.accessed}x`);
}
console.log('');
}
if (delta) {
console.log(` Last Delta (${delta.elapsed} ago)`);
const sign = v => v > 0 ? `+${v}` : `${v}`;
console.log(` Nodes: ${sign(delta.nodes)}`);
console.log(` Edges: ${sign(delta.edges)}`);
console.log(` Confidence: ${delta.confidenceMean >= 0 ? '+' : ''}${delta.confidenceMean.toFixed(4)}`);
console.log(` Accesses: ${sign(delta.totalAccess)}`);
console.log('');
}
if (trend) {
console.log(` Trend (${trend.sessions} snapshots)`);
console.log(` Node growth: ${trend.nodeGrowth >= 0 ? '+' : ''}${trend.nodeGrowth}`);
console.log(` Edge growth: ${trend.edgeGrowth >= 0 ? '+' : ''}${trend.edgeGrowth}`);
console.log(` Confidence drift: ${trend.confidenceDrift >= 0 ? '+' : ''}${trend.confidenceDrift.toFixed(4)}`);
console.log(` Direction: ${trend.direction.toUpperCase()}`);
console.log('');
}
if (!delta && !trend) {
console.log(' No history yet — run more sessions to see deltas and trends.');
console.log('');
}
console.log(bar);
return report;
}
module.exports = { init, getContext, recordEdit, feedback, consolidate, stats };
// ── CLI entrypoint ──────────────────────────────────────────────────────────
if (require.main === module) {
const cmd = process.argv[2];
const jsonFlag = process.argv.includes('--json');
const cmds = {
init: () => { const r = init(); console.log(JSON.stringify(r)); },
stats: () => { stats(jsonFlag); },
consolidate: () => { const r = consolidate(); console.log(JSON.stringify(r)); },
};
if (cmd && cmds[cmd]) {
cmds[cmd]();
} else {
console.log('Usage: intelligence.cjs <stats|init|consolidate> [--json]');
console.log('');
console.log(' stats Show intelligence diagnostics and trends');
console.log(' stats --json Output as JSON for programmatic use');
console.log(' init Build graph and rank entries');
console.log(' consolidate Process pending insights and recompute');
}
}
+1 -26
View File
@@ -7,7 +7,7 @@
import initSqlJs from 'sql.js';
import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSync } from 'fs';
import { dirname, join, basename, resolve } from 'path';
import { dirname, join, basename } from 'path';
import { fileURLToPath } from 'url';
import { execSync } from 'child_process';
@@ -154,19 +154,7 @@ function countFilesAndLines(dir, ext = '.ts') {
try {
const entries = readdirSync(currentDir, { withFileTypes: true });
for (const entry of entries) {
// Validate entry name to prevent path traversal
if (entry.name.includes('..') || entry.name.includes('/') || entry.name.includes('\\')) {
continue;
}
const fullPath = join(currentDir, entry.name);
// Additional validation: ensure resolved path is within the base directory
const resolvedPath = resolve(fullPath);
const resolvedCurrentDir = resolve(currentDir);
if (!resolvedPath.startsWith(resolvedCurrentDir)) {
continue; // Path traversal attempt detected
}
if (entry.isDirectory() && !entry.name.includes('node_modules')) {
walk(fullPath);
} else if (entry.isFile() && entry.name.endsWith(ext)) {
@@ -221,20 +209,7 @@ function calculateModuleProgress(moduleDir) {
* Check security file status
*/
function checkSecurityFile(filename, minLines = 100) {
// Validate filename to prevent path traversal
if (filename.includes('..') || filename.includes('/') || filename.includes('\\')) {
return false;
}
const filePath = join(V3_DIR, '@claude-flow/security/src', filename);
// Additional validation: ensure resolved path is within the expected directory
const resolvedPath = resolve(filePath);
const expectedDir = resolve(join(V3_DIR, '@claude-flow/security/src'));
if (!resolvedPath.startsWith(expectedDir)) {
return false; // Path traversal attempt detected
}
if (!existsSync(filePath)) return false;
try {
-8
View File
@@ -100,14 +100,6 @@ const commands = {
return session;
},
get: (key) => {
if (!fs.existsSync(SESSION_FILE)) return null;
try {
const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
return key ? (session.context || {})[key] : session.context;
} catch { return null; }
},
metric: (name) => {
if (!fs.existsSync(SESSION_FILE)) {
return null;
+181 -638
View File
@@ -1,31 +1,32 @@
#!/usr/bin/env node
/**
* Claude Flow V3 Statusline Generator (Optimized)
* Claude Flow V3 Statusline Generator
* Displays real-time V3 implementation progress and system status
*
* Usage: node statusline.cjs [--json] [--compact]
*
* Performance notes:
* - Single git execSync call (combines branch + status + upstream)
* - No recursive file reading (only stat/readdir, never read test contents)
* - No ps aux calls (uses process.memoryUsage() + file-based metrics)
* - Strict 2s timeout on all execSync calls
* - Shared settings cache across functions
* IMPORTANT: This file uses .cjs extension to work in ES module projects.
* The require() syntax is intentional for CommonJS compatibility.
*/
/* eslint-disable @typescript-eslint/no-var-requires */
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const os = require('os');
// Configuration
const CONFIG = {
enabled: true,
showProgress: true,
showSecurity: true,
showSwarm: true,
showHooks: true,
showPerformance: true,
refreshInterval: 5000,
maxAgents: 15,
topology: 'hierarchical-mesh',
};
const CWD = process.cwd();
// ANSI colors
const c = {
reset: '\x1b[0m',
@@ -46,728 +47,270 @@ const c = {
brightWhite: '\x1b[1;37m',
};
// Safe execSync with strict timeout (returns empty string on failure)
// Validates command to prevent command injection
function safeExec(cmd, timeoutMs = 2000) {
// Get user info
function getUserInfo() {
let name = 'user';
let gitBranch = '';
let modelName = 'Opus 4.5';
try {
// Validate command to prevent command injection
// Only allow commands that match safe patterns (no shell metacharacters)
if (typeof cmd !== 'string') {
return '';
}
// Check for dangerous shell metacharacters that could allow injection
const dangerousChars = /[;&|`$(){}[\]<>'"\\]/;
if (dangerousChars.test(cmd)) {
// If dangerous chars found, only allow if it's a known safe pattern
// Allow 'sh -c' with single-quoted script (already escaped)
const safeShPattern = /^sh\s+-c\s+'[^']*'$/;
if (!safeShPattern.test(cmd)) {
console.warn('safeExec: Command contains potentially dangerous characters');
return '';
}
}
return execSync(cmd, {
encoding: 'utf-8',
timeout: timeoutMs,
stdio: ['pipe', 'pipe', 'pipe'],
}).trim();
} catch {
return '';
}
}
// Safe JSON file reader (returns null on failure)
function readJSON(filePath) {
try {
if (fs.existsSync(filePath)) {
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
}
} catch { /* ignore */ }
return null;
}
// Safe file stat (returns null on failure)
function safeStat(filePath) {
try {
return fs.statSync(filePath);
} catch { /* ignore */ }
return null;
}
// Shared settings cache — read once, used by multiple functions
let _settingsCache = undefined;
function getSettings() {
if (_settingsCache !== undefined) return _settingsCache;
_settingsCache = readJSON(path.join(CWD, '.claude', 'settings.json'))
|| readJSON(path.join(CWD, '.claude', 'settings.local.json'))
|| null;
return _settingsCache;
}
// ─── Data Collection (all pure-Node.js or single-exec) ──────────
// Get all git info in ONE shell call
function getGitInfo() {
const result = {
name: 'user', gitBranch: '', modified: 0, untracked: 0,
staged: 0, ahead: 0, behind: 0,
};
// Single shell: get user.name, branch, porcelain status, and upstream diff
const script = [
'git config user.name 2>/dev/null || echo user',
'echo "---SEP---"',
'git branch --show-current 2>/dev/null',
'echo "---SEP---"',
'git status --porcelain 2>/dev/null',
'echo "---SEP---"',
'git rev-list --left-right --count HEAD...@{upstream} 2>/dev/null || echo "0 0"',
].join('; ');
const raw = safeExec("sh -c '" + script + "'", 3000);
if (!raw) return result;
const parts = raw.split('---SEP---').map(s => s.trim());
if (parts.length >= 4) {
result.name = parts[0] || 'user';
result.gitBranch = parts[1] || '';
// Parse porcelain status
if (parts[2]) {
for (const line of parts[2].split('\n')) {
if (!line || line.length < 2) continue;
const x = line[0], y = line[1];
if (x === '?' && y === '?') { result.untracked++; continue; }
if (x !== ' ' && x !== '?') result.staged++;
if (y !== ' ' && y !== '?') result.modified++;
}
}
// Parse ahead/behind
const ab = (parts[3] || '0 0').split(/\s+/);
result.ahead = parseInt(ab[0]) || 0;
result.behind = parseInt(ab[1]) || 0;
name = execSync('git config user.name 2>/dev/null || echo "user"', { encoding: 'utf-8' }).trim();
gitBranch = execSync('git branch --show-current 2>/dev/null || echo ""', { encoding: 'utf-8' }).trim();
} catch (e) {
// Ignore errors
}
return result;
return { name, gitBranch, modelName };
}
// Detect model name from Claude config (pure file reads, no exec)
function getModelName() {
try {
const claudeConfig = readJSON(path.join(os.homedir(), '.claude.json'));
if (claudeConfig && claudeConfig.projects) {
for (const [projectPath, projectConfig] of Object.entries(claudeConfig.projects)) {
if (CWD === projectPath || CWD.startsWith(projectPath + '/')) {
const usage = projectConfig.lastModelUsage;
if (usage) {
const ids = Object.keys(usage);
if (ids.length > 0) {
let modelId = ids[ids.length - 1];
let latest = 0;
for (const id of ids) {
const ts = usage[id] && usage[id].lastUsedAt ? new Date(usage[id].lastUsedAt).getTime() : 0;
if (ts > latest) { latest = ts; modelId = id; }
}
if (modelId.includes('opus')) return 'Opus 4.6';
if (modelId.includes('sonnet')) return 'Sonnet 4.6';
if (modelId.includes('haiku')) return 'Haiku 4.5';
return modelId.split('-').slice(1, 3).join(' ');
}
}
break;
}
}
}
} catch { /* ignore */ }
// Fallback: settings.json model field
const settings = getSettings();
if (settings && settings.model) {
const m = settings.model;
if (m.includes('opus')) return 'Opus 4.6';
if (m.includes('sonnet')) return 'Sonnet 4.6';
if (m.includes('haiku')) return 'Haiku 4.5';
}
return 'Claude Code';
}
// Get learning stats from memory database (pure stat calls)
// Get learning stats from memory database
function getLearningStats() {
const memoryPaths = [
path.join(CWD, '.swarm', 'memory.db'),
path.join(CWD, '.claude-flow', 'memory.db'),
path.join(CWD, '.claude', 'memory.db'),
path.join(CWD, 'data', 'memory.db'),
path.join(CWD, '.agentdb', 'memory.db'),
path.join(process.cwd(), '.swarm', 'memory.db'),
path.join(process.cwd(), '.claude', 'memory.db'),
path.join(process.cwd(), 'data', 'memory.db'),
];
let patterns = 0;
let sessions = 0;
let trajectories = 0;
// Try to read from sqlite database
for (const dbPath of memoryPaths) {
const stat = safeStat(dbPath);
if (stat) {
const sizeKB = stat.size / 1024;
const patterns = Math.floor(sizeKB / 2);
return {
patterns,
sessions: Math.max(1, Math.floor(patterns / 10)),
};
if (fs.existsSync(dbPath)) {
try {
// Count entries in memory file (rough estimate from file size)
const stats = fs.statSync(dbPath);
const sizeKB = stats.size / 1024;
// Estimate: ~2KB per pattern on average
patterns = Math.floor(sizeKB / 2);
sessions = Math.max(1, Math.floor(patterns / 10));
trajectories = Math.floor(patterns / 5);
break;
} catch (e) {
// Ignore
}
}
}
// Check session files count
let sessions = 0;
try {
const sessDir = path.join(CWD, '.claude', 'sessions');
if (fs.existsSync(sessDir)) {
sessions = fs.readdirSync(sessDir).filter(f => f.endsWith('.json')).length;
// Also check for session files
const sessionsPath = path.join(process.cwd(), '.claude', 'sessions');
if (fs.existsSync(sessionsPath)) {
try {
const sessionFiles = fs.readdirSync(sessionsPath).filter(f => f.endsWith('.json'));
sessions = Math.max(sessions, sessionFiles.length);
} catch (e) {
// Ignore
}
} catch { /* ignore */ }
}
return { patterns: 0, sessions };
return { patterns, sessions, trajectories };
}
// V3 progress from metrics files (pure file reads)
// Get V3 progress from learning state (grows as system learns)
function getV3Progress() {
const learning = getLearningStats();
// DDD progress based on actual learned patterns
// New install: 0 patterns = 0/5 domains, 0% DDD
// As patterns grow: 10+ patterns = 1 domain, 50+ = 2, 100+ = 3, 200+ = 4, 500+ = 5
let domainsCompleted = 0;
if (learning.patterns >= 500) domainsCompleted = 5;
else if (learning.patterns >= 200) domainsCompleted = 4;
else if (learning.patterns >= 100) domainsCompleted = 3;
else if (learning.patterns >= 50) domainsCompleted = 2;
else if (learning.patterns >= 10) domainsCompleted = 1;
const totalDomains = 5;
const dddData = readJSON(path.join(CWD, '.claude-flow', 'metrics', 'ddd-progress.json'));
let dddProgress = dddData ? (dddData.progress || 0) : 0;
let domainsCompleted = Math.min(5, Math.floor(dddProgress / 20));
if (dddProgress === 0 && learning.patterns > 0) {
if (learning.patterns >= 500) domainsCompleted = 5;
else if (learning.patterns >= 200) domainsCompleted = 4;
else if (learning.patterns >= 100) domainsCompleted = 3;
else if (learning.patterns >= 50) domainsCompleted = 2;
else if (learning.patterns >= 10) domainsCompleted = 1;
dddProgress = Math.floor((domainsCompleted / totalDomains) * 100);
}
const dddProgress = Math.min(100, Math.floor((domainsCompleted / totalDomains) * 100));
return {
domainsCompleted, totalDomains, dddProgress,
domainsCompleted,
totalDomains,
dddProgress,
patternsLearned: learning.patterns,
sessionsCompleted: learning.sessions,
sessionsCompleted: learning.sessions
};
}
// Security status (pure file reads)
// Get security status based on actual scans
function getSecurityStatus() {
// Check for security scan results in memory
const scanResultsPath = path.join(process.cwd(), '.claude', 'security-scans');
let cvesFixed = 0;
const totalCves = 3;
const auditData = readJSON(path.join(CWD, '.claude-flow', 'security', 'audit-status.json'));
if (auditData) {
return {
status: auditData.status || 'PENDING',
cvesFixed: auditData.cvesFixed || 0,
totalCves: auditData.totalCves || 3,
};
if (fs.existsSync(scanResultsPath)) {
try {
const scans = fs.readdirSync(scanResultsPath).filter(f => f.endsWith('.json'));
// Each successful scan file = 1 CVE addressed
cvesFixed = Math.min(totalCves, scans.length);
} catch (e) {
// Ignore
}
}
let cvesFixed = 0;
try {
const scanDir = path.join(CWD, '.claude', 'security-scans');
if (fs.existsSync(scanDir)) {
cvesFixed = Math.min(totalCves, fs.readdirSync(scanDir).filter(f => f.endsWith('.json')).length);
// Also check .swarm/security for audit results
const auditPath = path.join(process.cwd(), '.swarm', 'security');
if (fs.existsSync(auditPath)) {
try {
const audits = fs.readdirSync(auditPath).filter(f => f.includes('audit'));
cvesFixed = Math.min(totalCves, Math.max(cvesFixed, audits.length));
} catch (e) {
// Ignore
}
} catch { /* ignore */ }
}
const status = cvesFixed >= totalCves ? 'CLEAN' : cvesFixed > 0 ? 'IN_PROGRESS' : 'PENDING';
return {
status: cvesFixed >= totalCves ? 'CLEAN' : cvesFixed > 0 ? 'IN_PROGRESS' : 'PENDING',
status,
cvesFixed,
totalCves,
};
}
// Swarm status (pure file reads, NO ps aux)
// Get swarm status
function getSwarmStatus() {
const activityData = readJSON(path.join(CWD, '.claude-flow', 'metrics', 'swarm-activity.json'));
if (activityData && activityData.swarm) {
return {
activeAgents: activityData.swarm.agent_count || 0,
maxAgents: CONFIG.maxAgents,
coordinationActive: activityData.swarm.coordination_active || activityData.swarm.active || false,
};
}
const progressData = readJSON(path.join(CWD, '.claude-flow', 'metrics', 'v3-progress.json'));
if (progressData && progressData.swarm) {
return {
activeAgents: progressData.swarm.activeAgents || progressData.swarm.agent_count || 0,
maxAgents: progressData.swarm.totalAgents || CONFIG.maxAgents,
coordinationActive: progressData.swarm.active || (progressData.swarm.activeAgents > 0),
};
}
return { activeAgents: 0, maxAgents: CONFIG.maxAgents, coordinationActive: false };
}
// System metrics (uses process.memoryUsage() — no shell spawn)
function getSystemMetrics() {
const memoryMB = Math.floor(process.memoryUsage().heapUsed / 1024 / 1024);
const learning = getLearningStats();
const agentdb = getAgentDBStats();
// Intelligence from learning.json
const learningData = readJSON(path.join(CWD, '.claude-flow', 'metrics', 'learning.json'));
let intelligencePct = 0;
let contextPct = 0;
if (learningData && learningData.intelligence && learningData.intelligence.score !== undefined) {
intelligencePct = Math.min(100, Math.floor(learningData.intelligence.score));
} else {
const fromPatterns = learning.patterns > 0 ? Math.min(100, Math.floor(learning.patterns / 10)) : 0;
const fromVectors = agentdb.vectorCount > 0 ? Math.min(100, Math.floor(agentdb.vectorCount / 100)) : 0;
intelligencePct = Math.max(fromPatterns, fromVectors);
}
// Maturity fallback (pure fs checks, no git exec)
if (intelligencePct === 0) {
let score = 0;
if (fs.existsSync(path.join(CWD, '.claude'))) score += 15;
const srcDirs = ['src', 'lib', 'app', 'packages', 'v3'];
for (const d of srcDirs) { if (fs.existsSync(path.join(CWD, d))) { score += 15; break; } }
const testDirs = ['tests', 'test', '__tests__', 'spec'];
for (const d of testDirs) { if (fs.existsSync(path.join(CWD, d))) { score += 10; break; } }
const cfgFiles = ['package.json', 'tsconfig.json', 'pyproject.toml', 'Cargo.toml', 'go.mod'];
for (const f of cfgFiles) { if (fs.existsSync(path.join(CWD, f))) { score += 5; break; } }
intelligencePct = Math.min(100, score);
}
if (learningData && learningData.sessions && learningData.sessions.total !== undefined) {
contextPct = Math.min(100, learningData.sessions.total * 5);
} else {
contextPct = Math.min(100, Math.floor(learning.sessions * 5));
}
// Sub-agents from file metrics (no ps aux)
let subAgents = 0;
const activityData = readJSON(path.join(CWD, '.claude-flow', 'metrics', 'swarm-activity.json'));
if (activityData && activityData.processes && activityData.processes.estimated_agents) {
subAgents = activityData.processes.estimated_agents;
}
return { memoryMB, contextPct, intelligencePct, subAgents };
}
// ADR status (count files only — don't read contents)
function getADRStatus() {
const complianceData = readJSON(path.join(CWD, '.claude-flow', 'metrics', 'adr-compliance.json'));
if (complianceData) {
const checks = complianceData.checks || {};
const total = Object.keys(checks).length;
const impl = Object.values(checks).filter(c => c.compliant).length;
return { count: total, implemented: impl, compliance: complianceData.compliance || 0 };
}
// Fallback: just count ADR files (don't read them)
const adrPaths = [
path.join(CWD, 'v3', 'implementation', 'adrs'),
path.join(CWD, 'docs', 'adrs'),
path.join(CWD, '.claude-flow', 'adrs'),
];
for (const adrPath of adrPaths) {
try {
if (fs.existsSync(adrPath)) {
const files = fs.readdirSync(adrPath).filter(f =>
f.endsWith('.md') && (f.startsWith('ADR-') || f.startsWith('adr-') || /^\d{4}-/.test(f))
);
const implemented = Math.floor(files.length * 0.7);
const compliance = files.length > 0 ? Math.floor((implemented / files.length) * 100) : 0;
return { count: files.length, implemented, compliance };
}
} catch { /* ignore */ }
}
return { count: 0, implemented: 0, compliance: 0 };
}
// Hooks status (shared settings cache)
function getHooksStatus() {
let enabled = 0;
const total = 17;
const settings = getSettings();
if (settings && settings.hooks) {
for (const category of Object.keys(settings.hooks)) {
const h = settings.hooks[category];
if (Array.isArray(h) && h.length > 0) enabled++;
}
}
let activeAgents = 0;
let coordinationActive = false;
try {
const hooksDir = path.join(CWD, '.claude', 'hooks');
if (fs.existsSync(hooksDir)) {
const hookFiles = fs.readdirSync(hooksDir).filter(f => f.endsWith('.js') || f.endsWith('.sh')).length;
enabled = Math.max(enabled, hookFiles);
}
} catch { /* ignore */ }
const ps = execSync('ps aux 2>/dev/null | grep -c agentic-flow || echo "0"', { encoding: 'utf-8' });
activeAgents = Math.max(0, parseInt(ps.trim()) - 1);
coordinationActive = activeAgents > 0;
} catch (e) {
// Ignore errors
}
return { enabled, total };
return {
activeAgents,
maxAgents: CONFIG.maxAgents,
coordinationActive,
};
}
// AgentDB stats (pure stat calls)
function getAgentDBStats() {
let vectorCount = 0;
let dbSizeKB = 0;
let namespaces = 0;
let hasHnsw = false;
// Get system metrics (dynamic based on actual state)
function getSystemMetrics() {
let memoryMB = 0;
let subAgents = 0;
const dbFiles = [
path.join(CWD, '.swarm', 'memory.db'),
path.join(CWD, '.claude-flow', 'memory.db'),
path.join(CWD, '.claude', 'memory.db'),
path.join(CWD, 'data', 'memory.db'),
];
for (const f of dbFiles) {
const stat = safeStat(f);
if (stat) {
dbSizeKB = stat.size / 1024;
vectorCount = Math.floor(dbSizeKB / 2);
namespaces = 1;
break;
}
try {
const mem = execSync('ps aux | grep -E "(node|agentic|claude)" | grep -v grep | awk \'{sum += \$6} END {print int(sum/1024)}\'', { encoding: 'utf-8' });
memoryMB = parseInt(mem.trim()) || 0;
} catch (e) {
// Fallback
memoryMB = Math.floor(process.memoryUsage().heapUsed / 1024 / 1024);
}
if (vectorCount === 0) {
const dbDirs = [
path.join(CWD, '.claude-flow', 'agentdb'),
path.join(CWD, '.swarm', 'agentdb'),
path.join(CWD, '.agentdb'),
];
for (const dir of dbDirs) {
try {
if (fs.existsSync(dir) && fs.statSync(dir).isDirectory()) {
const files = fs.readdirSync(dir);
namespaces = files.filter(f => f.endsWith('.db') || f.endsWith('.sqlite')).length;
for (const file of files) {
const stat = safeStat(path.join(dir, file));
if (stat && stat.isFile()) dbSizeKB += stat.size / 1024;
}
vectorCount = Math.floor(dbSizeKB / 2);
break;
}
} catch { /* ignore */ }
}
// Get learning stats for intelligence %
const learning = getLearningStats();
// Intelligence % based on learned patterns (0 patterns = 0%, 1000+ = 100%)
const intelligencePct = Math.min(100, Math.floor((learning.patterns / 10) * 1));
// Context % based on session history (0 sessions = 0%, grows with usage)
const contextPct = Math.min(100, Math.floor(learning.sessions * 5));
// Count active sub-agents from process list
try {
const agents = execSync('ps aux 2>/dev/null | grep -c "claude-flow.*agent" || echo "0"', { encoding: 'utf-8' });
subAgents = Math.max(0, parseInt(agents.trim()) - 1);
} catch (e) {
// Ignore
}
const hnswPaths = [
path.join(CWD, '.swarm', 'hnsw.index'),
path.join(CWD, '.claude-flow', 'hnsw.index'),
];
for (const p of hnswPaths) {
const stat = safeStat(p);
if (stat) {
hasHnsw = true;
vectorCount = Math.max(vectorCount, Math.floor(stat.size / 512));
break;
}
}
return { vectorCount, dbSizeKB: Math.floor(dbSizeKB), namespaces, hasHnsw };
return {
memoryMB,
contextPct,
intelligencePct,
subAgents,
};
}
// Test stats (count files only — NO reading file contents)
function getTestStats() {
let testFiles = 0;
function countTestFiles(dir, depth) {
if (depth === undefined) depth = 0;
if (depth > 2) return;
try {
if (!fs.existsSync(dir)) return;
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {
countTestFiles(path.join(dir, entry.name), depth + 1);
} else if (entry.isFile()) {
const n = entry.name;
if (n.includes('.test.') || n.includes('.spec.') || n.includes('_test.') || n.includes('_spec.')) {
testFiles++;
}
}
}
} catch { /* ignore */ }
}
var testDirNames = ['tests', 'test', '__tests__', 'v3/__tests__'];
for (var i = 0; i < testDirNames.length; i++) {
countTestFiles(path.join(CWD, testDirNames[i]));
}
countTestFiles(path.join(CWD, 'src'));
return { testFiles, testCases: testFiles * 4 };
}
// Integration status (shared settings + file checks)
function getIntegrationStatus() {
const mcpServers = { total: 0, enabled: 0 };
const settings = getSettings();
if (settings && settings.mcpServers && typeof settings.mcpServers === 'object') {
const servers = Object.keys(settings.mcpServers);
mcpServers.total = servers.length;
mcpServers.enabled = settings.enabledMcpjsonServers
? settings.enabledMcpjsonServers.filter(s => servers.includes(s)).length
: servers.length;
}
if (mcpServers.total === 0) {
const mcpConfig = readJSON(path.join(CWD, '.mcp.json'))
|| readJSON(path.join(os.homedir(), '.claude', 'mcp.json'));
if (mcpConfig && mcpConfig.mcpServers) {
const s = Object.keys(mcpConfig.mcpServers);
mcpServers.total = s.length;
mcpServers.enabled = s.length;
}
}
const hasDatabase = ['.swarm/memory.db', '.claude-flow/memory.db', 'data/memory.db']
.some(p => fs.existsSync(path.join(CWD, p)));
const hasApi = !!(process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY);
return { mcpServers, hasDatabase, hasApi };
}
// Session stats (pure file reads)
function getSessionStats() {
var sessionPaths = ['.claude-flow/session.json', '.claude/session.json'];
for (var i = 0; i < sessionPaths.length; i++) {
const data = readJSON(path.join(CWD, sessionPaths[i]));
if (data && data.startTime) {
const diffMs = Date.now() - new Date(data.startTime).getTime();
const mins = Math.floor(diffMs / 60000);
const duration = mins < 60 ? mins + 'm' : Math.floor(mins / 60) + 'h' + (mins % 60) + 'm';
return { duration: duration };
}
}
return { duration: '' };
}
// ─── Rendering ──────────────────────────────────────────────────
// Generate progress bar
function progressBar(current, total) {
const width = 5;
const filled = Math.round((current / total) * width);
return '[' + '\u25CF'.repeat(filled) + '\u25CB'.repeat(width - filled) + ']';
const empty = width - filled;
return '[' + '\u25CF'.repeat(filled) + '\u25CB'.repeat(empty) + ']';
}
// Generate full statusline
function generateStatusline() {
const git = getGitInfo();
// Prefer model name from Claude Code stdin data, fallback to file-based detection
const modelName = getModelFromStdin() || getModelName();
const ctxInfo = getContextFromStdin();
const costInfo = getCostFromStdin();
const user = getUserInfo();
const progress = getV3Progress();
const security = getSecurityStatus();
const swarm = getSwarmStatus();
const system = getSystemMetrics();
const adrs = getADRStatus();
const hooks = getHooksStatus();
const agentdb = getAgentDBStats();
const tests = getTestStats();
const session = getSessionStats();
const integration = getIntegrationStatus();
const lines = [];
// Header
let header = c.bold + c.brightPurple + '\u258A Claude Flow V3 ' + c.reset;
header += (swarm.coordinationActive ? c.brightCyan : c.dim) + '\u25CF ' + c.brightCyan + git.name + c.reset;
if (git.gitBranch) {
header += ' ' + c.dim + '\u2502' + c.reset + ' ' + c.brightBlue + '\u23C7 ' + git.gitBranch + c.reset;
const changes = git.modified + git.staged + git.untracked;
if (changes > 0) {
let ind = '';
if (git.staged > 0) ind += c.brightGreen + '+' + git.staged + c.reset;
if (git.modified > 0) ind += c.brightYellow + '~' + git.modified + c.reset;
if (git.untracked > 0) ind += c.dim + '?' + git.untracked + c.reset;
header += ' ' + ind;
}
if (git.ahead > 0) header += ' ' + c.brightGreen + '\u2191' + git.ahead + c.reset;
if (git.behind > 0) header += ' ' + c.brightRed + '\u2193' + git.behind + c.reset;
}
header += ' ' + c.dim + '\u2502' + c.reset + ' ' + c.purple + modelName + c.reset;
// Show session duration from Claude Code stdin if available, else from local files
const duration = costInfo ? costInfo.duration : session.duration;
if (duration) header += ' ' + c.dim + '\u2502' + c.reset + ' ' + c.cyan + '\u23F1 ' + duration + c.reset;
// Show context usage from Claude Code stdin if available
if (ctxInfo && ctxInfo.usedPct > 0) {
const ctxColor = ctxInfo.usedPct >= 90 ? c.brightRed : ctxInfo.usedPct >= 70 ? c.brightYellow : c.brightGreen;
header += ' ' + c.dim + '\u2502' + c.reset + ' ' + ctxColor + '\u25CF ' + ctxInfo.usedPct + '% ctx' + c.reset;
}
// Show cost from Claude Code stdin if available
if (costInfo && costInfo.costUsd > 0) {
header += ' ' + c.dim + '\u2502' + c.reset + ' ' + c.brightYellow + '$' + costInfo.costUsd.toFixed(2) + c.reset;
// Header Line
let header = `${c.bold}${c.brightPurple} Claude Flow V3 ${c.reset}`;
header += `${swarm.coordinationActive ? c.brightCyan : c.dim}${c.brightCyan}${user.name}${c.reset}`;
if (user.gitBranch) {
header += ` ${c.dim}${c.reset} ${c.brightBlue}${user.gitBranch}${c.reset}`;
}
header += ` ${c.dim}${c.reset} ${c.purple}${user.modelName}${c.reset}`;
lines.push(header);
// Separator
lines.push(c.dim + '\u2500'.repeat(53) + c.reset);
lines.push(`${c.dim}─────────────────────────────────────────────────────${c.reset}`);
// Line 1: DDD Domains
// Line 1: DDD Domain Progress
const domainsColor = progress.domainsCompleted >= 3 ? c.brightGreen : progress.domainsCompleted > 0 ? c.yellow : c.red;
let perfIndicator;
if (agentdb.hasHnsw && agentdb.vectorCount > 0) {
const speedup = agentdb.vectorCount > 10000 ? '12500x' : agentdb.vectorCount > 1000 ? '150x' : '10x';
perfIndicator = c.brightGreen + '\u26A1 HNSW ' + speedup + c.reset;
} else if (progress.patternsLearned > 0) {
const pk = progress.patternsLearned >= 1000 ? (progress.patternsLearned / 1000).toFixed(1) + 'k' : String(progress.patternsLearned);
perfIndicator = c.brightYellow + '\uD83D\uDCDA ' + pk + ' patterns' + c.reset;
} else {
perfIndicator = c.dim + '\u26A1 target: 150x-12500x' + c.reset;
}
lines.push(
c.brightCyan + '\uD83C\uDFD7\uFE0F DDD Domains' + c.reset + ' ' + progressBar(progress.domainsCompleted, progress.totalDomains) + ' ' +
domainsColor + progress.domainsCompleted + c.reset + '/' + c.brightWhite + progress.totalDomains + c.reset + ' ' + perfIndicator
`${c.brightCyan}🏗️ DDD Domains${c.reset} ${progressBar(progress.domainsCompleted, progress.totalDomains)} ` +
`${domainsColor}${progress.domainsCompleted}${c.reset}/${c.brightWhite}${progress.totalDomains}${c.reset} ` +
`${c.brightYellow}⚡ 1.0x${c.reset} ${c.dim}${c.reset} ${c.brightYellow}2.49x-7.47x${c.reset}`
);
// Line 2: Swarm + Hooks + CVE + Memory + Intelligence
const swarmInd = swarm.coordinationActive ? c.brightGreen + '\u25C9' + c.reset : c.dim + '\u25CB' + c.reset;
// Line 2: Swarm + CVE + Memory + Context + Intelligence
const swarmIndicator = swarm.coordinationActive ? `${c.brightGreen}${c.reset}` : `${c.dim}${c.reset}`;
const agentsColor = swarm.activeAgents > 0 ? c.brightGreen : c.red;
const secIcon = security.status === 'CLEAN' ? '\uD83D\uDFE2' : security.status === 'IN_PROGRESS' ? '\uD83D\uDFE1' : '\uD83D\uDD34';
const secColor = security.status === 'CLEAN' ? c.brightGreen : security.status === 'IN_PROGRESS' ? c.brightYellow : c.brightRed;
const hooksColor = hooks.enabled > 0 ? c.brightGreen : c.dim;
const intellColor = system.intelligencePct >= 80 ? c.brightGreen : system.intelligencePct >= 40 ? c.brightYellow : c.dim;
let securityIcon = security.status === 'CLEAN' ? '🟢' : security.status === 'IN_PROGRESS' ? '🟡' : '🔴';
let securityColor = security.status === 'CLEAN' ? c.brightGreen : security.status === 'IN_PROGRESS' ? c.brightYellow : c.brightRed;
lines.push(
c.brightYellow + '\uD83E\uDD16 Swarm' + c.reset + ' ' + swarmInd + ' [' + agentsColor + String(swarm.activeAgents).padStart(2) + c.reset + '/' + c.brightWhite + swarm.maxAgents + c.reset + '] ' +
c.brightPurple + '\uD83D\uDC65 ' + system.subAgents + c.reset + ' ' +
c.brightBlue + '\uD83E\uDE9D ' + hooksColor + hooks.enabled + c.reset + '/' + c.brightWhite + hooks.total + c.reset + ' ' +
secIcon + ' ' + secColor + 'CVE ' + security.cvesFixed + c.reset + '/' + c.brightWhite + security.totalCves + c.reset + ' ' +
c.brightCyan + '\uD83D\uDCBE ' + system.memoryMB + 'MB' + c.reset + ' ' +
intellColor + '\uD83E\uDDE0 ' + String(system.intelligencePct).padStart(3) + '%' + c.reset
`${c.brightYellow}🤖 Swarm${c.reset} ${swarmIndicator} [${agentsColor}${String(swarm.activeAgents).padStart(2)}${c.reset}/${c.brightWhite}${swarm.maxAgents}${c.reset}] ` +
`${c.brightPurple}👥 ${system.subAgents}${c.reset} ` +
`${securityIcon} ${securityColor}CVE ${security.cvesFixed}${c.reset}/${c.brightWhite}${security.totalCves}${c.reset} ` +
`${c.brightCyan}💾 ${system.memoryMB}MB${c.reset} ` +
`${c.brightGreen}📂 ${String(system.contextPct).padStart(3)}%${c.reset} ` +
`${c.dim}🧠 ${String(system.intelligencePct).padStart(3)}%${c.reset}`
);
// Line 3: Architecture
// Line 3: Architecture status
const dddColor = progress.dddProgress >= 50 ? c.brightGreen : progress.dddProgress > 0 ? c.yellow : c.red;
const adrColor = adrs.count > 0 ? (adrs.implemented === adrs.count ? c.brightGreen : c.yellow) : c.dim;
const adrDisplay = adrs.compliance > 0 ? adrColor + '\u25CF' + adrs.compliance + '%' + c.reset : adrColor + '\u25CF' + adrs.implemented + '/' + adrs.count + c.reset;
lines.push(
c.brightPurple + '\uD83D\uDD27 Architecture' + c.reset + ' ' +
c.cyan + 'ADRs' + c.reset + ' ' + adrDisplay + ' ' + c.dim + '\u2502' + c.reset + ' ' +
c.cyan + 'DDD' + c.reset + ' ' + dddColor + '\u25CF' + String(progress.dddProgress).padStart(3) + '%' + c.reset + ' ' + c.dim + '\u2502' + c.reset + ' ' +
c.cyan + 'Security' + c.reset + ' ' + secColor + '\u25CF' + security.status + c.reset
);
// Line 4: AgentDB, Tests, Integration
const hnswInd = agentdb.hasHnsw ? c.brightGreen + '\u26A1' + c.reset : '';
const sizeDisp = agentdb.dbSizeKB >= 1024 ? (agentdb.dbSizeKB / 1024).toFixed(1) + 'MB' : agentdb.dbSizeKB + 'KB';
const vectorColor = agentdb.vectorCount > 0 ? c.brightGreen : c.dim;
const testColor = tests.testFiles > 0 ? c.brightGreen : c.dim;
let integStr = '';
if (integration.mcpServers.total > 0) {
const mcpCol = integration.mcpServers.enabled === integration.mcpServers.total ? c.brightGreen :
integration.mcpServers.enabled > 0 ? c.brightYellow : c.red;
integStr += c.cyan + 'MCP' + c.reset + ' ' + mcpCol + '\u25CF' + integration.mcpServers.enabled + '/' + integration.mcpServers.total + c.reset;
}
if (integration.hasDatabase) integStr += (integStr ? ' ' : '') + c.brightGreen + '\u25C6' + c.reset + 'DB';
if (integration.hasApi) integStr += (integStr ? ' ' : '') + c.brightGreen + '\u25C6' + c.reset + 'API';
if (!integStr) integStr = c.dim + '\u25CF none' + c.reset;
lines.push(
c.brightCyan + '\uD83D\uDCCA AgentDB' + c.reset + ' ' +
c.cyan + 'Vectors' + c.reset + ' ' + vectorColor + '\u25CF' + agentdb.vectorCount + hnswInd + c.reset + ' ' + c.dim + '\u2502' + c.reset + ' ' +
c.cyan + 'Size' + c.reset + ' ' + c.brightWhite + sizeDisp + c.reset + ' ' + c.dim + '\u2502' + c.reset + ' ' +
c.cyan + 'Tests' + c.reset + ' ' + testColor + '\u25CF' + tests.testFiles + c.reset + ' ' + c.dim + '(~' + tests.testCases + ' cases)' + c.reset + ' ' + c.dim + '\u2502' + c.reset + ' ' +
integStr
`${c.brightPurple}🔧 Architecture${c.reset} ` +
`${c.cyan}DDD${c.reset} ${dddColor}${String(progress.dddProgress).padStart(3)}%${c.reset} ${c.dim}${c.reset} ` +
`${c.cyan}Security${c.reset} ${securityColor}${security.status}${c.reset} ${c.dim}${c.reset} ` +
`${c.cyan}Memory${c.reset} ${c.brightGreen}●AgentDB${c.reset} ${c.dim}${c.reset} ` +
`${c.cyan}Integration${c.reset} ${swarm.coordinationActive ? c.brightCyan : c.dim}${c.reset}`
);
return lines.join('\n');
}
// JSON output
// Generate JSON data
function generateJSON() {
const git = getGitInfo();
return {
user: { name: git.name, gitBranch: git.gitBranch, modelName: getModelName() },
user: getUserInfo(),
v3Progress: getV3Progress(),
security: getSecurityStatus(),
swarm: getSwarmStatus(),
system: getSystemMetrics(),
adrs: getADRStatus(),
hooks: getHooksStatus(),
agentdb: getAgentDBStats(),
tests: getTestStats(),
git: { modified: git.modified, untracked: git.untracked, staged: git.staged, ahead: git.ahead, behind: git.behind },
performance: {
flashAttentionTarget: '2.49x-7.47x',
searchImprovement: '150x-12,500x',
memoryReduction: '50-75%',
},
lastUpdated: new Date().toISOString(),
};
}
// ─── Stdin reader (Claude Code pipes session JSON) ──────────────
// Claude Code sends session JSON via stdin (model, context, cost, etc.)
// Read it synchronously so the script works both:
// 1. When invoked by Claude Code (stdin has JSON)
// 2. When invoked manually from terminal (stdin is empty/tty)
let _stdinData = null;
function getStdinData() {
if (_stdinData !== undefined && _stdinData !== null) return _stdinData;
try {
// Check if stdin is a TTY (manual run) — skip reading
if (process.stdin.isTTY) { _stdinData = null; return null; }
// Read stdin synchronously via fd 0
const chunks = [];
const buf = Buffer.alloc(4096);
let bytesRead;
try {
while ((bytesRead = fs.readSync(0, buf, 0, buf.length, null)) > 0) {
chunks.push(buf.slice(0, bytesRead));
}
} catch { /* EOF or read error */ }
const raw = Buffer.concat(chunks).toString('utf-8').trim();
if (raw && raw.startsWith('{')) {
_stdinData = JSON.parse(raw);
} else {
_stdinData = null;
}
} catch {
_stdinData = null;
}
return _stdinData;
}
// Override model detection to prefer stdin data from Claude Code
function getModelFromStdin() {
const data = getStdinData();
if (data && data.model && data.model.display_name) return data.model.display_name;
return null;
}
// Get context window info from Claude Code session
function getContextFromStdin() {
const data = getStdinData();
if (data && data.context_window) {
return {
usedPct: Math.floor(data.context_window.used_percentage || 0),
remainingPct: Math.floor(data.context_window.remaining_percentage || 100),
};
}
return null;
}
// Get cost info from Claude Code session
function getCostFromStdin() {
const data = getStdinData();
if (data && data.cost) {
const durationMs = data.cost.total_duration_ms || 0;
const mins = Math.floor(durationMs / 60000);
const secs = Math.floor((durationMs % 60000) / 1000);
return {
costUsd: data.cost.total_cost_usd || 0,
duration: mins > 0 ? mins + 'm' + secs + 's' : secs + 's',
linesAdded: data.cost.total_lines_added || 0,
linesRemoved: data.cost.total_lines_removed || 0,
};
}
return null;
}
// ─── Main ───────────────────────────────────────────────────────
// Main
if (process.argv.includes('--json')) {
console.log(JSON.stringify(generateJSON(), null, 2));
} else if (process.argv.includes('--compact')) {
+1 -1
View File
@@ -18,7 +18,7 @@ const CONFIG = {
showSwarm: true,
showHooks: true,
showPerformance: true,
refreshInterval: 30000,
refreshInterval: 5000,
maxAgents: 15,
topology: 'hierarchical-mesh',
};
BIN
View File
Binary file not shown.
-1
View File
@@ -1 +0,0 @@
{"sessionId":"d80c93c2-51b7-42e8-a0fc-dc47cff1200f","pid":45748,"acquiredAt":1779668018388}
+88 -98
View File
@@ -2,24 +2,70 @@
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"matcher": "^(Write|Edit|MultiEdit)$",
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" pre-bash",
"timeout": 5000
"command": "[ -n \"$TOOL_INPUT_file_path\" ] && npx @claude-flow/cli@latest hooks pre-edit --file \"$TOOL_INPUT_file_path\" 2>/dev/null || true",
"timeout": 5000,
"continueOnError": true
}
]
},
{
"matcher": "^Bash$",
"hooks": [
{
"type": "command",
"command": "[ -n \"$TOOL_INPUT_command\" ] && npx @claude-flow/cli@latest hooks pre-command --command \"$TOOL_INPUT_command\" 2>/dev/null || true",
"timeout": 5000,
"continueOnError": true
}
]
},
{
"matcher": "^Task$",
"hooks": [
{
"type": "command",
"command": "[ -n \"$TOOL_INPUT_prompt\" ] && npx @claude-flow/cli@latest hooks pre-task --task-id \"task-$(date +%s)\" --description \"$TOOL_INPUT_prompt\" 2>/dev/null || true",
"timeout": 5000,
"continueOnError": true
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"matcher": "^(Write|Edit|MultiEdit)$",
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" post-edit",
"timeout": 10000
"command": "[ -n \"$TOOL_INPUT_file_path\" ] && npx @claude-flow/cli@latest hooks post-edit --file \"$TOOL_INPUT_file_path\" --success \"${TOOL_SUCCESS:-true}\" 2>/dev/null || true",
"timeout": 5000,
"continueOnError": true
}
]
},
{
"matcher": "^Bash$",
"hooks": [
{
"type": "command",
"command": "[ -n \"$TOOL_INPUT_command\" ] && npx @claude-flow/cli@latest hooks post-command --command \"$TOOL_INPUT_command\" --success \"${TOOL_SUCCESS:-true}\" 2>/dev/null || true",
"timeout": 5000,
"continueOnError": true
}
]
},
{
"matcher": "^Task$",
"hooks": [
{
"type": "command",
"command": "[ -n \"$TOOL_RESULT_agent_id\" ] && npx @claude-flow/cli@latest hooks post-task --task-id \"$TOOL_RESULT_agent_id\" --success \"${TOOL_SUCCESS:-true}\" 2>/dev/null || true",
"timeout": 5000,
"continueOnError": true
}
]
}
@@ -29,8 +75,9 @@
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" route",
"timeout": 10000
"command": "[ -n \"$PROMPT\" ] && npx @claude-flow/cli@latest hooks route --task \"$PROMPT\" || true",
"timeout": 5000,
"continueOnError": true
}
]
}
@@ -40,24 +87,15 @@
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" session-restore",
"timeout": 15000
"command": "npx @claude-flow/cli@latest daemon start --quiet 2>/dev/null || true",
"timeout": 5000,
"continueOnError": true
},
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/auto-memory-hook.mjs\" import",
"timeout": 8000
}
]
}
],
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" session-end",
"timeout": 10000
"command": "[ -n \"$SESSION_ID\" ] && npx @claude-flow/cli@latest hooks session-restore --session-id \"$SESSION_ID\" 2>/dev/null || true",
"timeout": 10000,
"continueOnError": true
}
]
}
@@ -67,49 +105,42 @@
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/auto-memory-hook.mjs\" sync",
"timeout": 10000
"command": "echo '{\"ok\": true}'",
"timeout": 1000
}
]
}
],
"PreCompact": [
"Notification": [
{
"matcher": "manual",
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" compact-manual"
},
"command": "[ -n \"$NOTIFICATION_MESSAGE\" ] && npx @claude-flow/cli@latest memory store --namespace notifications --key \"notify-$(date +%s)\" --value \"$NOTIFICATION_MESSAGE\" 2>/dev/null || true",
"timeout": 3000,
"continueOnError": true
}
]
}
],
"PermissionRequest": [
{
"matcher": "^mcp__claude-flow__.*$",
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" session-end",
"timeout": 5000
"command": "echo '{\"decision\": \"allow\", \"reason\": \"claude-flow MCP tool auto-approved\"}'",
"timeout": 1000
}
]
},
{
"matcher": "auto",
"matcher": "^Bash\\(npx @?claude-flow.*\\)$",
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" compact-auto"
},
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" session-end",
"timeout": 6000
}
]
}
],
"SubagentStart": [
{
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" status",
"timeout": 3000
"command": "echo '{\"decision\": \"allow\", \"reason\": \"claude-flow CLI auto-approved\"}'",
"timeout": 1000
}
]
}
@@ -117,56 +148,24 @@
},
"statusLine": {
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/statusline.cjs\""
"command": "npx @claude-flow/cli@latest hooks statusline 2>/dev/null || node .claude/helpers/statusline.cjs 2>/dev/null || echo \"▊ Claude Flow V3\"",
"refreshMs": 5000,
"enabled": true
},
"permissions": {
"allow": [
"Bash(npx @claude-flow*)",
"Bash(npx claude-flow*)",
"Bash(node .claude/*)",
"mcp__claude-flow__:*"
"Bash(npx @claude-flow/*)",
"mcp__claude-flow__*"
],
"deny": []
},
"attribution": {
"commit": "Co-Authored-By: claude-flow <ruv@ruv.net>",
"pr": "🤖 Generated with [claude-flow](https://github.com/ruvnet/claude-flow)"
},
"env": {
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1",
"CLAUDE_FLOW_V3_ENABLED": "true",
"CLAUDE_FLOW_HOOKS_ENABLED": "true"
},
"claudeFlow": {
"version": "3.0.0",
"enabled": true,
"modelPreferences": {
"default": "claude-opus-4-6",
"routing": "claude-haiku-4-5-20251001"
},
"agentTeams": {
"enabled": true,
"teammateMode": "auto",
"taskListEnabled": true,
"mailboxEnabled": true,
"coordination": {
"autoAssignOnIdle": true,
"trainPatternsOnComplete": true,
"notifyLeadOnComplete": true,
"sharedMemoryNamespace": "agent-teams"
},
"hooks": {
"teammateIdle": {
"enabled": true,
"autoAssign": true,
"checkTaskList": true
},
"taskCompleted": {
"enabled": true,
"trainPatterns": true,
"notifyLead": true
}
}
"default": "claude-opus-4-5-20251101",
"routing": "claude-3-5-haiku-20241022"
},
"swarm": {
"topology": "hierarchical-mesh",
@@ -174,16 +173,7 @@
},
"memory": {
"backend": "hybrid",
"enableHNSW": true,
"learningBridge": {
"enabled": true
},
"memoryGraph": {
"enabled": true
},
"agentScopes": {
"enabled": true
}
"enableHNSW": true
},
"neural": {
"enabled": true
-6
View File
@@ -1,6 +0,0 @@
{
"enabledMcpjsonServers": [
"claude-flow"
],
"enableAllProjectMcpServers": true
}
-204
View File
@@ -1,204 +0,0 @@
---
name: browser
description: Web browser automation with AI-optimized snapshots for claude-flow agents
version: 1.0.0
triggers:
- /browser
- browse
- web automation
- scrape
- navigate
- screenshot
tools:
- browser/open
- browser/snapshot
- browser/click
- browser/fill
- browser/screenshot
- browser/close
---
# Browser Automation Skill
Web browser automation using agent-browser with AI-optimized snapshots. Reduces context by 93% using element refs (@e1, @e2) instead of full DOM.
## Core Workflow
```bash
# 1. Navigate to page
agent-browser open <url>
# 2. Get accessibility tree with element refs
agent-browser snapshot -i # -i = interactive elements only
# 3. Interact using refs from snapshot
agent-browser click @e2
agent-browser fill @e3 "text"
# 4. Re-snapshot after page changes
agent-browser snapshot -i
```
## Quick Reference
### Navigation
| Command | Description |
|---------|-------------|
| `open <url>` | Navigate to URL |
| `back` | Go back |
| `forward` | Go forward |
| `reload` | Reload page |
| `close` | Close browser |
### Snapshots (AI-Optimized)
| Command | Description |
|---------|-------------|
| `snapshot` | Full accessibility tree |
| `snapshot -i` | Interactive elements only (buttons, links, inputs) |
| `snapshot -c` | Compact (remove empty elements) |
| `snapshot -d 3` | Limit depth to 3 levels |
| `screenshot [path]` | Capture screenshot (base64 if no path) |
### Interaction
| Command | Description |
|---------|-------------|
| `click <sel>` | Click element |
| `fill <sel> <text>` | Clear and fill input |
| `type <sel> <text>` | Type with key events |
| `press <key>` | Press key (Enter, Tab, etc.) |
| `hover <sel>` | Hover element |
| `select <sel> <val>` | Select dropdown option |
| `check/uncheck <sel>` | Toggle checkbox |
| `scroll <dir> [px]` | Scroll page |
### Get Info
| Command | Description |
|---------|-------------|
| `get text <sel>` | Get text content |
| `get html <sel>` | Get innerHTML |
| `get value <sel>` | Get input value |
| `get attr <sel> <attr>` | Get attribute |
| `get title` | Get page title |
| `get url` | Get current URL |
### Wait
| Command | Description |
|---------|-------------|
| `wait <selector>` | Wait for element |
| `wait <ms>` | Wait milliseconds |
| `wait --text "text"` | Wait for text |
| `wait --url "pattern"` | Wait for URL |
| `wait --load networkidle` | Wait for load state |
### Sessions
| Command | Description |
|---------|-------------|
| `--session <name>` | Use isolated session |
| `session list` | List active sessions |
## Selectors
### Element Refs (Recommended)
```bash
# Get refs from snapshot
agent-browser snapshot -i
# Output: button "Submit" [ref=e2]
# Use ref to interact
agent-browser click @e2
```
### CSS Selectors
```bash
agent-browser click "#submit"
agent-browser fill ".email-input" "test@test.com"
```
### Semantic Locators
```bash
agent-browser find role button click --name "Submit"
agent-browser find label "Email" fill "test@test.com"
agent-browser find testid "login-btn" click
```
## Examples
### Login Flow
```bash
agent-browser open https://example.com/login
agent-browser snapshot -i
agent-browser fill @e2 "user@example.com"
agent-browser fill @e3 "password123"
agent-browser click @e4
agent-browser wait --url "**/dashboard"
```
### Form Submission
```bash
agent-browser open https://example.com/contact
agent-browser snapshot -i
agent-browser fill @e1 "John Doe"
agent-browser fill @e2 "john@example.com"
agent-browser fill @e3 "Hello, this is my message"
agent-browser click @e4
agent-browser wait --text "Thank you"
```
### Data Extraction
```bash
agent-browser open https://example.com/products
agent-browser snapshot -i
# Iterate through product refs
agent-browser get text @e1 # Product name
agent-browser get text @e2 # Price
agent-browser get attr @e3 href # Link
```
### Multi-Session (Swarm)
```bash
# Session 1: Navigator
agent-browser --session nav open https://example.com
agent-browser --session nav state save auth.json
# Session 2: Scraper (uses same auth)
agent-browser --session scrape state load auth.json
agent-browser --session scrape open https://example.com/data
agent-browser --session scrape snapshot -i
```
## Integration with Claude Flow
### MCP Tools
All browser operations are available as MCP tools with `browser/` prefix:
- `browser/open`
- `browser/snapshot`
- `browser/click`
- `browser/fill`
- `browser/screenshot`
- etc.
### Memory Integration
```bash
# Store successful patterns
npx @claude-flow/cli memory store --namespace browser-patterns --key "login-flow" --value "snapshot->fill->click->wait"
# Retrieve before similar task
npx @claude-flow/cli memory search --query "login automation"
```
### Hooks
```bash
# Pre-browse hook (get context)
npx @claude-flow/cli hooks pre-edit --file "browser-task.ts"
# Post-browse hook (record success)
npx @claude-flow/cli hooks post-task --task-id "browse-1" --success true
```
## Tips
1. **Always use snapshots** - They're optimized for AI with refs
2. **Prefer `-i` flag** - Gets only interactive elements, smaller output
3. **Use refs, not selectors** - More reliable, deterministic
4. **Re-snapshot after navigation** - Page state changes
5. **Use sessions for parallel work** - Each session is isolated
@@ -11,8 +11,8 @@ Implements ReasoningBank's adaptive learning system for AI agents to learn from
## Prerequisites
- agentic-flow v3.0.0-alpha.1+
- AgentDB v3.0.0-alpha.10+ (for persistence)
- agentic-flow v1.5.11+
- AgentDB v1.0.4+ (for persistence)
- Node.js 18+
## Quick Start
+1 -1
View File
@@ -11,7 +11,7 @@ Orchestrates multi-agent swarms using agentic-flow's advanced coordination syste
## Prerequisites
- agentic-flow v3.0.0-alpha.1+
- agentic-flow v1.5.11+
- Node.js 18+
- Understanding of distributed systems (helpful)
+130 -6
View File
@@ -1,8 +1,132 @@
target/
.git/
*.log
# Git
.git
.gitignore
.gitattributes
# Documentation
*.md
docs/
references/
plans/
# Development files
.vscode/
.idea/
*.swp
*.swo
*~
# Python
__pycache__/
*.pyc
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# Virtual environments
.env
node_modules/
.claude/
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Testing
.tox/
.coverage
.coverage.*
.cache
.pytest_cache/
htmlcov/
.nox/
coverage.xml
*.cover
.hypothesis/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# Environments
.env.local
.env.development
.env.test
.env.production
# Logs
logs/
*.log
# Runtime data
pids/
*.pid
*.seed
*.pid.lock
# Temporary files
tmp/
temp/
.tmp/
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# IDE
*.sublime-project
*.sublime-workspace
# Deployment
docker-compose*.yml
Dockerfile*
.dockerignore
k8s/
terraform/
ansible/
monitoring/
logging/
# CI/CD
.github/
.gitlab-ci.yml
# Models (exclude large model files from build context)
*.pth
*.pt
*.onnx
models/*.bin
models/*.safetensors
# Data files
data/
*.csv
*.json
*.parquet
# Backup files
*.bak
*.backup
-58
View File
@@ -1,58 +0,0 @@
version: 2
updates:
# Keep all third-party GitHub Actions on verified, pinned commit SHAs.
# Pairs with the SHA pinning in security-scan.yml and ci.yml so that
# future bumps stay automated and reviewable rather than drifting back
# to mutable @master / @main refs. See issue #442.
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
labels:
- dependencies
- github-actions
# Mobile app npm deps. Includes the @xmldom/xmldom, node-forge, and
# picomatch advisories from #442 plus axios and any future surface.
- package-ecosystem: npm
directory: /ui/mobile
schedule:
interval: weekly
open-pull-requests-limit: 10
labels:
- dependencies
- mobile
# Desktop UI npm deps. Direct vite devDep currently has a HIGH advisory
# (dev-server-only path traversal); track future bumps automatically.
- package-ecosystem: npm
directory: /v2/crates/wifi-densepose-desktop/ui
schedule:
interval: weekly
open-pull-requests-limit: 5
labels:
- dependencies
- desktop
# Python deps used by v1/ and the FastAPI service. requirements.txt is
# only loosely pinned; let Dependabot surface upstream CVE bumps.
- package-ecosystem: pip
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 10
labels:
- dependencies
- python
# Rust workspace (15+ crates). cargo audit is not currently wired into
# any workflow, so Dependabot is the primary automated bump path.
- package-ecosystem: cargo
directory: /v2
schedule:
interval: weekly
open-pull-requests-limit: 10
labels:
- dependencies
- rust
@@ -1,94 +0,0 @@
name: AetherArena harness gate (ADR-149)
# Runs the AetherArena scoring harness as a PR build gate. Every PR that touches
# the scorer, the metrics, or the benchmark scaffold must keep the deterministic
# score hash stable (ADR-149 §2.5 determinism_gate). If the scoring maths changes,
# the hash moves and this gate fails until `expected_score.sha256` is regenerated
# and reviewed — so scorer drift can never land silently.
#
# This is the "a PR that runs the harness as part of the build process" requirement.
on:
pull_request:
paths:
- 'v2/crates/wifi-densepose-train/src/ruview_metrics.rs'
- 'v2/crates/wifi-densepose-train/src/ablation.rs'
- 'v2/crates/wifi-densepose-train/src/bin/aa_score_runner.rs'
- 'aether-arena/**'
- '.github/workflows/aether-arena-harness.yml'
push:
branches: ['feat/adr-149-aether-arena']
workflow_dispatch:
permissions:
contents: read
pull-requests: write
jobs:
harness-gate:
name: Run AA scorer harness (determinism gate)
runs-on: ubuntu-latest
defaults:
run:
working-directory: v2
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
run: rustup show && rustc --version
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
v2/target
key: aa-harness-${{ runner.os }}-${{ hashFiles('v2/Cargo.lock') }}
# 1. Build the pure-Rust scorer (no torch / no GPU → fast PR gate).
- name: Build AA score runner
run: cargo build -p wifi-densepose-train --bin aa_score_runner --no-default-features
# 2. Determinism gate: the committed expected hash must still match. A
# non-zero exit here fails the PR.
- name: Run determinism gate
run: cargo run -q -p wifi-densepose-train --bin aa_score_runner --no-default-features
# 3. Repeatability analysis (witness chain): the harness must produce one
# identical proof hash across many runs — any nondeterminism fails here.
- name: Repeatability analysis (16 runs)
run: cargo run -q -p wifi-densepose-train --bin aa_score_runner --no-default-features -- --repeat 16
# 4. Real-scoring smoke: score a sample prediction against the public smoke
# split, exercising the actual model-scoring path (not just the fixture).
- name: Real-scoring smoke test
run: |
cargo run -q -p wifi-densepose-train --bin aa_score_runner --no-default-features -- \
--split ../aether-arena/fixtures/smoke_split.json \
--pred ../aether-arena/fixtures/smoke_pred.json --json
# 5. Witness ledger chain integrity: the append-only results ledger must
# verify (every prev_hash link + row_hash intact = no silent edits).
- name: Verify witness ledger chain
working-directory: aether-arena/ledger
run: python3 ledger_tools.py verify
# 6. Emit the witness row + repeatability into the PR run summary.
- name: Witness row → job summary
if: always()
run: |
ROW=$(cargo run -q -p wifi-densepose-train --bin aa_score_runner --no-default-features -- --json)
REP=$(cargo run -q -p wifi-densepose-train --bin aa_score_runner --no-default-features -- --repeat 16)
{
echo "## AetherArena harness gate (witness chain)"
echo ""
echo "Deterministic witness (ADR-149 §2.2 / proof + repeatability):"
echo '```json'
echo "$ROW"
echo "$REP"
echo '```'
echo ""
echo "If the determinism gate failed, the scoring maths changed: regenerate with"
echo '`cargo run -p wifi-densepose-train --bin aa_score_runner --no-default-features -- --generate-hash > aether-arena/fixtures/expected_score.sha256` and review the diff.'
} >> "$GITHUB_STEP_SUMMARY"
@@ -1,99 +0,0 @@
name: BFLD MQTT Integration
# Runs the env-gated mosquitto integration tests from iters 24 + 29 of the
# BFLD rollout (ADR-118 / ADR-122 §2.2). Spins up an eclipse-mosquitto:2
# service container, exports BFLD_MQTT_BROKER, runs `cargo test --features
# mqtt`. Local developers can reproduce with:
#
# scoop install mosquitto # Windows
# # or: docker run -p 1883:1883 eclipse-mosquitto:2
# BFLD_MQTT_BROKER=tcp://localhost:1883 \
# cargo test -p wifi-densepose-bfld --features mqtt
on:
push:
branches:
- main
- 'feat/adr-118-*'
- 'feat/bfld-*'
paths:
- 'v2/crates/wifi-densepose-bfld/**'
- '.github/workflows/bfld-mqtt-integration.yml'
pull_request:
paths:
- 'v2/crates/wifi-densepose-bfld/**'
- '.github/workflows/bfld-mqtt-integration.yml'
workflow_dispatch:
jobs:
mqtt-live-broker:
name: cargo test --features mqtt (live mosquitto)
runs-on: ubuntu-latest
timeout-minutes: 15
services:
mosquitto:
image: eclipse-mosquitto:2
ports:
- 1883:1883
# Allow anonymous connections — local-only CI broker, no exposure
# to the public internet, never touches production credentials.
options: >-
--health-cmd "mosquitto_pub -h localhost -t healthcheck -m ping || exit 1"
--health-interval 5s
--health-timeout 3s
--health-retries 10
env:
BFLD_MQTT_BROKER: tcp://localhost:1883
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
RUSTFLAGS: -D warnings
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: Cache cargo registry + target
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
v2/target
key: bfld-mqtt-${{ runner.os }}-${{ hashFiles('v2/Cargo.lock') }}
- name: Wait for mosquitto to be ready
run: |
for i in {1..20}; do
if nc -z localhost 1883; then
echo "mosquitto reachable on port 1883 (attempt $i)"
exit 0
fi
echo "waiting for mosquitto ($i/20)..."
sleep 1
done
echo "mosquitto never became reachable" >&2
exit 1
- name: cargo test --no-default-features (baseline regression)
working-directory: v2
run: cargo test -p wifi-densepose-bfld --no-default-features
- name: cargo test (default features)
working-directory: v2
run: cargo test -p wifi-densepose-bfld
- name: cargo test --features mqtt (incl. live mosquitto roundtrip)
working-directory: v2
run: cargo test -p wifi-densepose-bfld --features mqtt
- name: cargo clippy --features mqtt (lint gate)
working-directory: v2
run: cargo clippy -p wifi-densepose-bfld --features mqtt --all-targets -- -D warnings
continue-on-error: true
+4 -9
View File
@@ -45,17 +45,12 @@ jobs:
- name: Determine deployment environment
id: determine-env
env:
# Use environment variable to prevent shell injection
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_REF: ${{ github.ref }}
GITHUB_INPUT_ENVIRONMENT: ${{ github.event.inputs.environment }}
run: |
if [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]]; then
echo "environment=$GITHUB_INPUT_ENVIRONMENT" >> $GITHUB_OUTPUT
elif [[ "$GITHUB_REF" == "refs/heads/main" ]]; then
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo "environment=${{ github.event.inputs.environment }}" >> $GITHUB_OUTPUT
elif [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
echo "environment=staging" >> $GITHUB_OUTPUT
elif [[ "$GITHUB_REF" == refs/tags/v* ]]; then
elif [[ "${{ github.ref }}" == refs/tags/v* ]]; then
echo "environment=production" >> $GITHUB_OUTPUT
else
echo "environment=staging" >> $GITHUB_OUTPUT
+34 -156
View File
@@ -2,7 +2,7 @@ name: Continuous Integration
on:
push:
branches: [ main, develop, 'feature/*', 'feat/*', 'hotfix/*' ]
branches: [ main, develop, 'feature/*', 'hotfix/*' ]
pull_request:
branches: [ main, develop ]
workflow_dispatch:
@@ -15,50 +15,38 @@ env:
jobs:
# Code Quality and Security Checks
# The Python codebase moved to `archive/v1/` when the runtime was rewritten in
# Rust under `v2/`. The lint/format/type/scan checks below still run against
# the archive for hygiene, but with `continue-on-error: true` everywhere — the
# archive is frozen reference code, not active development, so a stale lint
# rule shouldn't gate PRs to the Rust workspace.
code-quality:
name: Code Quality & Security
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout code
continue-on-error: true
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
continue-on-error: true
uses: actions/setup-python@v6
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: Install dependencies
continue-on-error: true
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install black flake8 mypy bandit safety
- name: Code formatting check (Black)
continue-on-error: true
run: black --check --diff archive/v1/src archive/v1/tests
run: black --check --diff src/ tests/
- name: Linting (Flake8)
continue-on-error: true
run: flake8 archive/v1/src archive/v1/tests --max-line-length=88 --extend-ignore=E203,W503
run: flake8 src/ tests/ --max-line-length=88 --extend-ignore=E203,W503
- name: Type checking (MyPy)
continue-on-error: true
run: mypy archive/v1/src --ignore-missing-imports
run: mypy src/ --ignore-missing-imports
- name: Security scan (Bandit)
run: bandit -r archive/v1/src -f json -o bandit-report.json
run: bandit -r src/ -f json -o bandit-report.json
continue-on-error: true
- name: Dependency vulnerability scan (Safety)
@@ -66,8 +54,7 @@ jobs:
continue-on-error: true
- name: Upload security reports
continue-on-error: true
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
if: always()
with:
name: security-reports
@@ -75,90 +62,11 @@ jobs:
bandit-report.json
safety-report.json
# Rust Workspace Tests
rust-tests:
name: Rust Workspace Tests
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
# `wifi-densepose-desktop` is a Tauri v2 app — `glib-sys`, `gtk-sys`,
# `webkit2gtk-sys`, etc. need the Linux dev libraries via pkg-config or the
# workspace test fails at the build step before any test runs (every recent
# main CI run has been red on this for exactly this reason). Install the
# standard Tauri-on-Ubuntu set.
- name: Install Tauri / GTK / serial system dev libraries
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libglib2.0-dev \
libgtk-3-dev \
libsoup-3.0-dev \
libjavascriptcoregtk-4.1-dev \
libwebkit2gtk-4.1-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
libxdo-dev \
libudev-dev \
libdbus-1-dev \
libssl-dev \
pkg-config
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
v2/target
key: ${{ runner.os }}-cargo-${{ hashFiles('v2/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: Run Rust tests
working-directory: v2
run: cargo test --workspace --no-default-features
- name: Run ADR-147 worldmodel tests
working-directory: v2
run: cargo test -p wifi-densepose-worldmodel --no-default-features
# ADR-134 CIR tests are behind the `cir` feature so the bench dependency
# (Criterion) only pulls when actually exercised. Run them as a separate
# step so a CIR-only regression is unambiguously attributable.
- name: Run ADR-134 CIR tests
working-directory: v2
run: cargo test -p wifi-densepose-signal --no-default-features --features cir --tests
# ADR-134 + ADR-028 witness guard. The CIR proof runner produces a
# bit-deterministic SHA-256 over CirEstimator output on the synthetic
# reference signal. Any algorithmic regression — changes to ISTA
# convergence, sensing matrix construction, soft-thresholding, or input
# padding — breaks the hash and fails the build. To regenerate after an
# *intentional* change:
# cd v2 && cargo run -p wifi-densepose-signal --bin cir_proof_runner \
# --release --no-default-features -- --generate-hash \
# > ../archive/v1/data/proof/expected_cir_features.sha256
- name: ADR-134 CIR witness proof (determinism guard)
run: bash scripts/verify-cir-proof.sh
- name: ADR-135 calibration witness proof (determinism guard)
run: bash scripts/verify-calibration-proof.sh
# Unit and Integration Tests
# Python pytest matrix — runs against the archived v1 Python tree.
# `continue-on-error: true` for the same reason as code-quality above:
# the archive is frozen reference, not blocking the Rust workspace PRs.
test:
name: Tests
runs-on: ubuntu-latest
continue-on-error: true
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.11', '3.12']
services:
@@ -187,52 +95,45 @@ jobs:
steps:
- name: Checkout code
continue-on-error: true
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
continue-on-error: true
uses: actions/setup-python@v6
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Install dependencies
continue-on-error: true
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pytest-cov pytest-xdist
- name: Run unit tests
continue-on-error: true
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_wifi_densepose
REDIS_URL: redis://localhost:6379/0
ENVIRONMENT: test
run: |
pytest archive/v1/tests/unit/ -v --cov=archive/v1/src --cov-report=xml --cov-report=html --junitxml=junit.xml
pytest tests/unit/ -v --cov=src --cov-report=xml --cov-report=html --junitxml=junit.xml
- name: Run integration tests
continue-on-error: true
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_wifi_densepose
REDIS_URL: redis://localhost:6379/0
ENVIRONMENT: test
run: |
pytest archive/v1/tests/integration/ -v --junitxml=integration-junit.xml
pytest tests/integration/ -v --junitxml=integration-junit.xml
- name: Upload coverage reports
continue-on-error: true
uses: codecov/codecov-action@v6
uses: codecov/codecov-action@v3
with:
file: ./coverage.xml
flags: unittests
name: codecov-umbrella
- name: Upload test results
continue-on-error: true
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
if: always()
with:
name: test-results-${{ matrix.python-version }}
@@ -242,21 +143,17 @@ jobs:
htmlcov/
# Performance and Load Tests
# NOTE: tests/performance/locustfile.py and the src.api.main app path both
# predate the v1→archive/v1 reorganisation. continue-on-error: true until a
# proper locust suite is added under archive/v1/tests/performance/.
performance-test:
name: Performance Tests
runs-on: ubuntu-latest
needs: [test]
continue-on-error: true
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v6
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
@@ -268,7 +165,6 @@ jobs:
pip install locust
- name: Start application
working-directory: archive/v1
run: |
uvicorn src.api.main:app --host 0.0.0.0 --port 8000 &
sleep 10
@@ -278,35 +174,24 @@ jobs:
locust -f tests/performance/locustfile.py --headless --users 50 --spawn-rate 5 --run-time 60s --host http://localhost:8000
- name: Upload performance results
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: performance-results
path: locust_report.html
# Docker Build and Test
# NOTE: the canonical Docker build for the sensing-server is now
# `.github/workflows/sensing-server-docker.yml` (multi-registry push, asset
# smoke tests, bearer-auth smoke tests — #520/#514/#443). This job predates
# that workflow, points at a non-existent root `Dockerfile` with a
# non-existent `target: production`, and pushes to a mis-cased image name —
# `continue-on-error: true` until it's deleted or rewired to call the new
# workflow, so it doesn't gate the rest of the pipeline.
docker-build:
name: Docker Build & Test
runs-on: ubuntu-latest
needs: [code-quality, test, rust-tests]
continue-on-error: true
needs: [code-quality, test]
steps:
- name: Checkout code
continue-on-error: true
uses: actions/checkout@v4
- name: Set up Docker Buildx
continue-on-error: true
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
continue-on-error: true
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
@@ -314,9 +199,8 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
continue-on-error: true
id: meta
uses: docker/metadata-action@v6
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
@@ -326,8 +210,7 @@ jobs:
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
continue-on-error: true
uses: docker/build-push-action@v7
uses: docker/build-push-action@v5
with:
context: .
target: production
@@ -339,7 +222,6 @@ jobs:
platforms: linux/amd64,linux/arm64
- name: Test Docker image
continue-on-error: true
run: |
docker run --rm -d --name test-container -p 8000:8000 ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
sleep 10
@@ -347,16 +229,14 @@ jobs:
docker stop test-container
- name: Run container security scan
continue-on-error: true
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results
continue-on-error: true
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'
@@ -372,7 +252,7 @@ jobs:
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v6
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
@@ -383,7 +263,6 @@ jobs:
pip install -r requirements.txt
- name: Generate OpenAPI spec
working-directory: archive/v1
run: |
python -c "
from src.api.main import app
@@ -393,7 +272,7 @@ jobs:
"
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
@@ -403,44 +282,43 @@ jobs:
notify:
name: Notify
runs-on: ubuntu-latest
needs: [code-quality, test, rust-tests, performance-test, docker-build, docs]
needs: [code-quality, test, performance-test, docker-build, docs]
if: always()
permissions:
contents: write # required by softprops/action-gh-release
# GitHub Actions does not allow `secrets.X` directly in step-level `if:`
# expressions — only `env.X`. Promote the secret to env at job scope so
# the gating expression below is parseable.
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
steps:
- name: Notify Slack on success
if: ${{ env.SLACK_WEBHOOK_URL != '' && needs.code-quality.result == 'success' && needs.test.result == 'success' && needs.docker-build.result == 'success' }}
if: ${{ needs.code-quality.result == 'success' && needs.test.result == 'success' && needs.docker-build.result == 'success' }}
uses: 8398a7/action-slack@v3
with:
status: success
channel: '#ci-cd'
text: '✅ CI pipeline completed successfully for ${{ github.ref }}'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
- name: Notify Slack on failure
if: ${{ env.SLACK_WEBHOOK_URL != '' && (needs.code-quality.result == 'failure' || needs.test.result == 'failure' || needs.docker-build.result == 'failure') }}
if: ${{ needs.code-quality.result == 'failure' || needs.test.result == 'failure' || needs.docker-build.result == 'failure' }}
uses: 8398a7/action-slack@v3
with:
status: failure
channel: '#ci-cd'
text: '❌ CI pipeline failed for ${{ github.ref }}'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
- name: Create GitHub Release
if: github.ref == 'refs/heads/main' && needs.docker-build.result == 'success'
uses: softprops/action-gh-release@v2
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ github.run_number }}
name: Release v${{ github.run_number }}
release_name: Release v${{ github.run_number }}
body: |
Automated release from CI pipeline
**Changes:**
${{ github.event.head_commit.message }}
**Docker Image:**
`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}`
draft: false
-149
View File
@@ -1,149 +0,0 @@
name: GitHub Clone Tracking → data/clone-data.rvf
# Persists rolling 14-day clone-traffic snapshots to data/clone-data.rvf in
# the ruvector JSONL RVF format. GitHub's /traffic/clones endpoint only
# retains the last 14 days server-side, so without this scheduled scrape
# the data is gone forever the moment it falls outside the window.
#
# Format: JSONL RVF
# - line 1 is a `metadata` segment that initializes the file
# - each subsequent run appends one `clone_snapshot` segment carrying the
# 14-day rollup PLUS per-day breakdown
# - file is idempotent: per-day entries are keyed by `timestamp` so a
# downstream reader can dedupe across overlapping snapshot windows
#
# Schedule: every 14 days (1st + 15th of each month, ~14-day cadence in
# practice). Workflow can also be dispatched manually for backfill or test.
on:
schedule:
# 01:23 UTC on the 1st and 15th of every month — close to 14-day cadence
# without cron's "every 14 days" monthly-reset weirdness. Picking :23
# avoids the cron herd on :00.
- cron: '23 1 1,15 * *'
workflow_dispatch:
permissions:
contents: write
concurrency:
group: clone-tracking
cancel-in-progress: false
jobs:
snapshot:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Fetch /traffic/clones + /traffic/views from GitHub
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir -p data
gh api repos/${{ github.repository }}/traffic/clones > /tmp/clones.json
gh api repos/${{ github.repository }}/traffic/views > /tmp/views.json
echo "--- clones rollup ---"
jq '{count, uniques, days: (.clones | length)}' /tmp/clones.json
echo "--- views rollup ---"
jq '{count, uniques, days: (.views | length)}' /tmp/views.json
- name: Append snapshot to data/clone-data.rvf
env:
REPO: ${{ github.repository }}
run: |
set -e
RVF="data/clone-data.rvf"
FETCHED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# Initialize the file with a metadata segment on first run.
if [ ! -f "$RVF" ]; then
echo "Initializing $RVF with metadata segment"
jq -n --arg repo "$REPO" --arg ts "$FETCHED_AT" '{
type: "metadata",
name: "ruview-clone-traffic-history",
version: "1.0.0",
schema: "ruvector.rvf.jsonl/v1",
format: "github-traffic-snapshots",
repo: $repo,
source: "GitHub Traffic API /repos/{repo}/traffic/{clones,views}",
policy: "GitHub retains only 14 days server-side; this file is the long-term record.",
segments: ["metadata", "clone_snapshot", "view_snapshot"],
created_at: $ts,
custom: {
cadence: "twice monthly (1st and 15th, ~14-day intervals)",
idempotency_key: "timestamp (per-day records de-duplicate across overlapping snapshot windows)"
}
}' >> "$RVF"
fi
# Append the clone snapshot.
jq --arg ts "$FETCHED_AT" '{
type: "clone_snapshot",
fetched_at: $ts,
window_count: .count,
window_uniques: .uniques,
per_day: .clones
}' /tmp/clones.json >> "$RVF"
# Append the views snapshot (free with the same auth).
jq --arg ts "$FETCHED_AT" '{
type: "view_snapshot",
fetched_at: $ts,
window_count: .count,
window_uniques: .uniques,
per_day: .views
}' /tmp/views.json >> "$RVF"
echo "--- RVF tail (last 4 lines) ---"
tail -4 "$RVF" | jq -c '{type, fetched_at, window_count, window_uniques}' || true
echo "--- file size ---"
wc -l "$RVF"
- name: Compute aggregates for the commit summary
id: agg
run: |
# Count distinct per-day entries across all snapshots so we can
# show "cumulative observed clones" in the commit message.
python3 - <<'PY'
import json, os
path = "data/clone-data.rvf"
per_day_clones = {}
per_day_views = {}
with open(path, encoding="utf-8") as f:
for line in f:
if not line.strip():
continue
d = json.loads(line)
if d.get("type") == "clone_snapshot":
for entry in d.get("per_day", []):
per_day_clones[entry["timestamp"]] = entry
elif d.get("type") == "view_snapshot":
for entry in d.get("per_day", []):
per_day_views[entry["timestamp"]] = entry
tot_clones = sum(e.get("count", 0) for e in per_day_clones.values())
tot_uniq_clones = sum(e.get("uniques", 0) for e in per_day_clones.values())
tot_views = sum(e.get("count", 0) for e in per_day_views.values())
tot_uniq_views = sum(e.get("uniques", 0) for e in per_day_views.values())
print(f"clone days observed: {len(per_day_clones)} total clones: {tot_clones:,} total unique cloners: {tot_uniq_clones:,}")
print(f"view days observed: {len(per_day_views)} total views: {tot_views:,} total unique viewers: {tot_uniq_views:,}")
with open(os.environ["GITHUB_OUTPUT"], "a") as out:
out.write(f"clones={tot_clones}\n")
out.write(f"clone_days={len(per_day_clones)}\n")
out.write(f"views={tot_views}\n")
out.write(f"view_days={len(per_day_views)}\n")
PY
- name: Commit + push if changed
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
if git diff --quiet data/clone-data.rvf; then
echo "no changes to commit"
exit 0
fi
git add data/clone-data.rvf
git commit -m "chore(traffic): clone snapshot — ${{ steps.agg.outputs.clone_days }} days observed → ${{ steps.agg.outputs.clones }} clones, ${{ steps.agg.outputs.view_days }} view-days → ${{ steps.agg.outputs.views }} views"
git push
-200
View File
@@ -1,200 +0,0 @@
name: Cog HA-Matter Release
# ADR-116 P8 — Build + sign + bundle the cog-ha-matter cog on a
# version tag. Upload to gs://cognitum-apps/ runs only when the
# GCP_CREDENTIALS + COGNITUM_OWNER_SIGNING_KEY secrets are set, so
# this workflow is safe to merge before the production credentials
# land — it'll bundle release artifacts to the workflow run page
# either way.
on:
push:
tags:
- 'cog-ha-matter-v*'
workflow_dispatch:
inputs:
dry_run:
description: 'Build + sign + bundle but skip GCS upload'
required: false
default: 'true'
env:
CARGO_TERM_COLOR: always
CRATE: cog-ha-matter
jobs:
build-x86_64:
name: Build x86_64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-unknown-linux-gnu
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
v2/target
key: cog-ha-matter-x86_64-${{ hashFiles('v2/Cargo.lock') }}
- name: Build release binary
working-directory: v2/crates/cog-ha-matter/cog
run: make build-x86_64
- name: Compute SHA-256
working-directory: v2/crates/cog-ha-matter/cog
run: make sign-x86_64
- name: Sign with Ed25519 (gated)
if: ${{ env.SIGNING_KEY != '' }}
env:
SIGNING_KEY: ${{ secrets.COGNITUM_OWNER_SIGNING_KEY }}
working-directory: v2/crates/cog-ha-matter/cog
run: |
printf '%s' "$SIGNING_KEY" \
| openssl pkeyutl -sign -inkey /dev/stdin -rawin \
-in dist/cog-ha-matter-x86_64.sha256 \
| base64 -w0 > dist/cog-ha-matter-x86_64.sig
echo "Signed cog-ha-matter-x86_64 ($(wc -c < dist/cog-ha-matter-x86_64.sig) bytes)"
- name: Upload workflow artifact
uses: actions/upload-artifact@v4
with:
name: cog-ha-matter-x86_64
path: |
v2/crates/cog-ha-matter/cog/dist/cog-ha-matter-x86_64
v2/crates/cog-ha-matter/cog/dist/cog-ha-matter-x86_64.sha256
v2/crates/cog-ha-matter/cog/dist/cog-ha-matter-x86_64.sig
if-no-files-found: warn
build-arm:
name: Build aarch64 (arm)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-unknown-linux-gnu
- name: Install cross-compiler
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
v2/target
key: cog-ha-matter-arm-${{ hashFiles('v2/Cargo.lock') }}
- name: Build release binary
working-directory: v2
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
run: |
cargo build -p cog-ha-matter --release --target aarch64-unknown-linux-gnu
mkdir -p crates/cog-ha-matter/cog/dist
cp target/aarch64-unknown-linux-gnu/release/cog-ha-matter \
crates/cog-ha-matter/cog/dist/cog-ha-matter-arm
# ^ matches Makefile's `dist/$(CRATE)-arm` so `make sign-arm` finds it
- name: Compute SHA-256
working-directory: v2/crates/cog-ha-matter/cog
run: make sign-arm
- name: Sign with Ed25519 (gated)
if: ${{ env.SIGNING_KEY != '' }}
env:
SIGNING_KEY: ${{ secrets.COGNITUM_OWNER_SIGNING_KEY }}
working-directory: v2/crates/cog-ha-matter/cog
run: |
printf '%s' "$SIGNING_KEY" \
| openssl pkeyutl -sign -inkey /dev/stdin -rawin \
-in dist/cog-ha-matter-arm.sha256 \
| base64 -w0 > dist/cog-ha-matter-arm.sig
echo "Signed cog-ha-matter-arm ($(wc -c < dist/cog-ha-matter-arm.sig) bytes)"
- name: Upload workflow artifact
uses: actions/upload-artifact@v4
with:
name: cog-ha-matter-arm
path: |
v2/crates/cog-ha-matter/cog/dist/cog-ha-matter-arm
v2/crates/cog-ha-matter/cog/dist/cog-ha-matter-arm.sha256
v2/crates/cog-ha-matter/cog/dist/cog-ha-matter-arm.sig
if-no-files-found: warn
publish-gcs:
name: Upload to GCS (gated)
needs: [build-x86_64, build-arm]
runs-on: ubuntu-latest
# Skip on dry-run dispatch; skip on tags when GCP_CREDENTIALS unset.
if: >
github.event_name == 'push' &&
vars.HAS_GCP_CREDENTIALS == 'true'
steps:
- uses: actions/checkout@v4
- name: Download x86_64 artifact
uses: actions/download-artifact@v4
with:
name: cog-ha-matter-x86_64
path: dist/
- name: Download arm artifact
uses: actions/download-artifact@v4
with:
name: cog-ha-matter-arm
path: dist/
- name: Auth to GCP
uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.GCP_CREDENTIALS }}
- name: Set up gcloud
uses: google-github-actions/setup-gcloud@v2
- name: Upload binaries + sidecars
run: |
gsutil cp dist/cog-ha-matter-x86_64 gs://cognitum-apps/cogs/x86_64/cog-ha-matter-x86_64
gsutil cp dist/cog-ha-matter-x86_64.sha256 gs://cognitum-apps/cogs/x86_64/cog-ha-matter-x86_64.sha256
gsutil cp dist/cog-ha-matter-arm gs://cognitum-apps/cogs/arm/cog-ha-matter-arm
gsutil cp dist/cog-ha-matter-arm.sha256 gs://cognitum-apps/cogs/arm/cog-ha-matter-arm.sha256
if [ -f dist/cog-ha-matter-x86_64.sig ]; then
gsutil cp dist/cog-ha-matter-x86_64.sig gs://cognitum-apps/cogs/x86_64/cog-ha-matter-x86_64.sig
fi
if [ -f dist/cog-ha-matter-arm.sig ]; then
gsutil cp dist/cog-ha-matter-arm.sig gs://cognitum-apps/cogs/arm/cog-ha-matter-arm.sig
fi
- name: Print app-registry.json snippet for the cognitum-one PR
run: |
for arch in arm x86_64; do
sha=$(cat dist/cog-cog-ha-matter-$arch.sha256)
sig=$([ -f dist/cog-cog-ha-matter-$arch.sig ] && cat dist/cog-cog-ha-matter-$arch.sig || echo "")
cat <<EOF
--- $arch ---
{
"id": "ha-matter",
"version": "${GITHUB_REF_NAME#cog-ha-matter-v}",
"binary_url": "https://storage.googleapis.com/cognitum-apps/cogs/$arch/cog-cog-ha-matter-$arch",
"binary_sha256": "$sha",
"binary_signature": "$sig",
"description": "Home Assistant + Matter Cognitum Seed cog (mDNS + witness chain)",
"min_seed_version": "0.6.0",
"installable_on": ["$arch"]
}
EOF
done
-46
View File
@@ -1,46 +0,0 @@
name: Dashboard a11y + cross-browser
# Runs axe-core a11y assertions on the built dashboard across
# Chromium, Firefox, and WebKit. Closes ADR-092 §11.5 (axe-core)
# and §11.8 (cross-browser).
on:
push:
branches: [main]
paths: ['dashboard/**', 'v2/crates/nvsim/**']
pull_request:
paths: ['dashboard/**']
workflow_dispatch:
permissions:
contents: read
jobs:
a11y:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with: { targets: wasm32-unknown-unknown }
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Build nvsim WASM
working-directory: v2
run: |
wasm-pack build crates/nvsim --target web \
--out-dir ../../dashboard/public/nvsim-pkg \
--release -- --no-default-features --features wasm
- uses: actions/setup-node@v6
with: { node-version: 20, cache: npm, cache-dependency-path: dashboard/package-lock.json }
- working-directory: dashboard
run: |
npm ci
npm install --save-dev @playwright/test @axe-core/playwright
npx playwright install --with-deps
npm run build
npx playwright test
-87
View File
@@ -1,87 +0,0 @@
name: nvsim Dashboard → GitHub Pages
# Deploys the nvsim Vite/Lit dashboard to gh-pages/nvsim/ — preserving
# the existing observatory/, pose-fusion/, and root index.html demos
# already published from gh-pages. ADR-092 §9.
on:
push:
branches: [main]
paths:
- 'v2/crates/nvsim/**'
- 'dashboard/**'
- '.github/workflows/dashboard-pages.yml'
workflow_dispatch:
permissions:
contents: write
concurrency:
group: dashboard-pages
cancel-in-progress: true
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout main
uses: actions/checkout@v4
- name: Install Rust + wasm32 target
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
v2/target
key: ${{ runner.os }}-cargo-nvsim-${{ hashFiles('v2/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-nvsim-
- name: Install wasm-pack
run: |
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
which wasm-pack
- name: Build nvsim WASM
working-directory: v2
run: |
wasm-pack build crates/nvsim \
--target web \
--out-dir ../../dashboard/public/nvsim-pkg \
--release \
-- --no-default-features --features wasm
- name: Setup Node 20
uses: actions/setup-node@v6
with:
node-version: 20
cache: npm
cache-dependency-path: dashboard/package-lock.json
- name: Install dashboard deps
working-directory: dashboard
run: npm ci
- name: Build dashboard
working-directory: dashboard
env:
NVSIM_BASE: /RuView/nvsim/
run: npm run build
- name: Deploy to gh-pages/nvsim/
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dashboard/dist
destination_dir: nvsim
# CRITICAL: preserves observatory/, pose-fusion/, root index.html
# and any other RuView demos already on gh-pages.
keep_files: true
commit_message: 'deploy(nvsim): ${{ github.sha }}'
user_name: 'github-actions[bot]'
user_email: 'github-actions[bot]@users.noreply.github.com'
-184
View File
@@ -1,184 +0,0 @@
name: Desktop Release
on:
push:
tags:
- 'desktop-v*'
workflow_dispatch:
inputs:
version:
description: 'Version to release (e.g., 0.4.0)'
required: true
default: '0.4.0'
attach_to_existing:
description: 'Attach to existing release tag (leave empty to create new)'
required: false
default: ''
env:
CARGO_TERM_COLOR: always
jobs:
build-macos:
name: Build macOS
runs-on: macos-latest
strategy:
matrix:
target: [aarch64-apple-darwin, x86_64-apple-darwin]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install frontend dependencies
working-directory: v2/crates/wifi-densepose-desktop/ui
run: npm ci
- name: Build frontend
working-directory: v2/crates/wifi-densepose-desktop/ui
run: npm run build
- name: Install Tauri CLI
run: cargo install tauri-cli --version "^2.0.0"
- name: Build Tauri app
working-directory: v2/crates/wifi-densepose-desktop
run: cargo tauri build --target ${{ matrix.target }}
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
- name: Get architecture name
id: arch
run: |
if [ "${{ matrix.target }}" = "aarch64-apple-darwin" ]; then
echo "arch=arm64" >> $GITHUB_OUTPUT
else
echo "arch=x64" >> $GITHUB_OUTPUT
fi
- name: Package macOS app
run: |
cd v2/target/${{ matrix.target }}/release/bundle/macos
zip -r "RuView-Desktop-${{ github.event.inputs.version || '0.4.0' }}-macos-${{ steps.arch.outputs.arch }}.zip" "RuView Desktop.app"
- name: Upload macOS artifact
uses: actions/upload-artifact@v4
with:
name: ruview-macos-${{ steps.arch.outputs.arch }}
path: v2/target/${{ matrix.target }}/release/bundle/macos/*.zip
build-windows:
name: Build Windows
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Install frontend dependencies
working-directory: v2/crates/wifi-densepose-desktop/ui
run: npm ci
- name: Build frontend
working-directory: v2/crates/wifi-densepose-desktop/ui
run: npm run build
- name: Install Tauri CLI
run: cargo install tauri-cli --version "^2.0.0"
- name: Build Tauri app
working-directory: v2/crates/wifi-densepose-desktop
run: cargo tauri build
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
- name: Upload Windows MSI artifact
uses: actions/upload-artifact@v4
with:
name: ruview-windows-msi
path: v2/target/release/bundle/msi/*.msi
- name: Upload Windows NSIS artifact
uses: actions/upload-artifact@v4
with:
name: ruview-windows-nsis
path: v2/target/release/bundle/nsis/*.exe
create-release:
name: Create Release
needs: [build-macos, build-windows]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: List artifacts
run: find artifacts -type f
- name: Create or Update Release
uses: softprops/action-gh-release@v2
with:
name: RuView Desktop v${{ github.event.inputs.version || '0.4.0' }}
tag_name: ${{ github.event.inputs.attach_to_existing || format('desktop-v{0}', github.event.inputs.version || '0.4.0') }}
draft: false
prerelease: false
generate_release_notes: ${{ github.event.inputs.attach_to_existing == '' }}
files: |
artifacts/**/*.zip
artifacts/**/*.msi
artifacts/**/*.exe
artifacts/**/*.dmg
body: |
## RuView Desktop v${{ github.event.inputs.version || '0.4.0' }}
WiFi-based human pose estimation desktop application.
### Downloads
| Platform | Architecture | Download |
|----------|--------------|----------|
| macOS | Apple Silicon (M1/M2/M3) | `RuView-Desktop-*-macos-arm64.zip` |
| macOS | Intel | `RuView-Desktop-*-macos-x64.zip` |
| Windows | x64 | `RuView-Desktop-*.msi` or `RuView-Desktop-*.exe` |
### Installation
**macOS:**
1. Download the appropriate `.zip` file for your Mac
2. Extract the zip file
3. Move `RuView Desktop.app` to your Applications folder
4. Right-click and select "Open" (first time only, to bypass Gatekeeper)
**Windows:**
1. Download the `.msi` installer
2. Run the installer
3. Launch RuView Desktop from the Start menu
### Requirements
- macOS 11.0+ (Big Sur or later)
- Windows 10/11 (64-bit)
-170
View File
@@ -1,170 +0,0 @@
name: Firmware CI
on:
push:
branches:
- '**'
tags:
# ESP32 firmware release tags — build + version-consistency guard (RuView#505).
- 'v*-esp32'
paths:
- 'firmware/**'
- '.github/workflows/firmware-ci.yml'
pull_request:
paths:
- 'firmware/**'
- '.github/workflows/firmware-ci.yml'
jobs:
version-guard:
name: Verify version.txt matches release tag
runs-on: ubuntu-latest
if: github.ref_type == 'tag'
steps:
- uses: actions/checkout@v4
- name: Check firmware version.txt == tag
run: |
# Tag form: vX.Y.Z-esp32 → expect version.txt to contain X.Y.Z
TAG="${GITHUB_REF_NAME}"
EXPECTED="${TAG#v}"
EXPECTED="${EXPECTED%-esp32}"
ACTUAL="$(tr -d '[:space:]' < firmware/esp32-csi-node/version.txt)"
echo "Tag: $TAG → expected version.txt: $EXPECTED | actual: $ACTUAL"
if [ "$EXPECTED" != "$ACTUAL" ]; then
echo "::error::firmware/esp32-csi-node/version.txt is '$ACTUAL' but tag '$TAG' expects '$EXPECTED'."
echo "::error::Bump version.txt and re-tag so esp_app_get_description()->version is correct (RuView#505)."
exit 1
fi
echo "version.txt matches the release tag."
build:
name: Build firmware (${{ matrix.target }} / ${{ matrix.variant }})
runs-on: ubuntu-latest
container:
image: espressif/idf:v5.4
strategy:
fail-fast: false
matrix:
include:
- variant: 8mb
target: esp32s3
sdkconfig: sdkconfig.defaults
partition_table_name: partitions_display.csv
size_limit_kb: 1100
artifact_app: esp32-csi-node.bin
artifact_pt: partition-table.bin
- variant: 4mb
target: esp32s3
sdkconfig: sdkconfig.defaults.4mb
partition_table_name: partitions_4mb.csv
size_limit_kb: 1100
artifact_app: esp32-csi-node-4mb.bin
artifact_pt: partition-table-4mb.bin
# ADR-110: ESP32-C6 research target (Wi-Fi 6 / 802.15.4 / TWT / LP-core)
- variant: c6-4mb
target: esp32c6
sdkconfig: sdkconfig.defaults
partition_table_name: partitions_4mb.csv
size_limit_kb: 1100
artifact_app: esp32-csi-node-c6.bin
artifact_pt: partition-table-c6.bin
steps:
- uses: actions/checkout@v4
- name: Build firmware (${{ matrix.variant }})
working-directory: firmware/esp32-csi-node
run: |
. $IDF_PATH/export.sh
# 4mb variant supplies its own sdkconfig.defaults overlay.
# c6-4mb variant relies on the auto-applied sdkconfig.defaults.esp32c6
# overlay (ESP-IDF auto-loads sdkconfig.defaults.$TARGET when present).
if [ "${{ matrix.variant }}" = "4mb" ]; then
cp "${{ matrix.sdkconfig }}" sdkconfig.defaults
fi
idf.py set-target ${{ matrix.target }}
idf.py build
- name: Build and run host-side ADR-110 unit tests
if: matrix.variant == 'c6-4mb'
working-directory: firmware/esp32-csi-node/test
run: |
make test_adr110
./test_adr110
- name: Verify binary size (< ${{ matrix.size_limit_kb }} KB gate)
working-directory: firmware/esp32-csi-node
run: |
BIN=build/esp32-csi-node.bin
SIZE=$(stat -c%s "$BIN")
MAX=$((${{ matrix.size_limit_kb }} * 1024))
echo "Binary size: $SIZE bytes ($(( SIZE / 1024 )) KB)"
echo "Size limit: $MAX bytes (${{ matrix.size_limit_kb }} KB)"
if [ "$SIZE" -gt "$MAX" ]; then
echo "::error::Firmware binary exceeds ${{ matrix.size_limit_kb }} KB size gate ($SIZE > $MAX)"
exit 1
fi
echo "Binary size OK: $SIZE <= $MAX"
- name: Verify flash image integrity
working-directory: firmware/esp32-csi-node
run: |
ERRORS=0
BIN=build/esp32-csi-node.bin
if [ ! -s "$BIN" ]; then
echo "::error::Binary not found or empty"
exit 1
fi
PT=build/partition_table/partition-table.bin
if [ -f "$PT" ]; then
MAGIC=$(od -A n -t x1 -N 2 "$PT" | tr -d ' ')
if [ "$MAGIC" != "aa50" ]; then
echo "::warning::Partition table magic mismatch: $MAGIC (expected aa50)"
ERRORS=$((ERRORS + 1))
fi
fi
BL=build/bootloader/bootloader.bin
if [ ! -s "$BL" ]; then
echo "::warning::Bootloader binary missing or empty"
ERRORS=$((ERRORS + 1))
fi
NONZERO=$(od -A n -t x1 -N 1024 "$BIN" | tr -d ' f\n' | wc -c)
if [ "$NONZERO" -lt 100 ]; then
echo "::error::Binary appears to be mostly padding (non-zero chars: $NONZERO)"
ERRORS=$((ERRORS + 1))
fi
if [ "$ERRORS" -gt 0 ]; then
echo "::warning::Flash image verification completed with $ERRORS warning(s)"
else
echo "Flash image integrity verified"
fi
- name: Stage release binaries with variant-specific names
working-directory: firmware/esp32-csi-node
run: |
mkdir -p release-staging
cp build/esp32-csi-node.bin release-staging/${{ matrix.artifact_app }}
cp build/partition_table/partition-table.bin release-staging/${{ matrix.artifact_pt }}
if [ "${{ matrix.variant }}" = "8mb" ]; then
cp build/bootloader/bootloader.bin release-staging/bootloader.bin
cp build/ota_data_initial.bin release-staging/ota_data_initial.bin
fi
ls -la release-staging/
- name: Check QEMU ESP32-S3 support status
run: |
echo "::notice::ESP32-S3 QEMU support is experimental in ESP-IDF v5.4. "
echo "Full smoke testing requires QEMU 8.2+ with xtensa-esp32s3 target."
echo "See: https://github.com/espressif/qemu/wiki"
- name: Upload firmware artifact (${{ matrix.variant }})
uses: actions/upload-artifact@v4
with:
name: esp32-csi-node-firmware-${{ matrix.variant }}
path: firmware/esp32-csi-node/release-staging/
retention-days: 90
-370
View File
@@ -1,370 +0,0 @@
name: Firmware QEMU Tests (ADR-061)
on:
push:
paths:
- 'firmware/**'
- 'scripts/qemu-esp32s3-test.sh'
- 'scripts/validate_qemu_output.py'
- 'scripts/generate_nvs_matrix.py'
- 'scripts/qemu_swarm.py'
- 'scripts/swarm_health.py'
- 'scripts/swarm_presets/**'
- '.github/workflows/firmware-qemu.yml'
pull_request:
paths:
- 'firmware/**'
- 'scripts/qemu-esp32s3-test.sh'
- 'scripts/validate_qemu_output.py'
- 'scripts/generate_nvs_matrix.py'
- 'scripts/qemu_swarm.py'
- 'scripts/swarm_health.py'
- 'scripts/swarm_presets/**'
- '.github/workflows/firmware-qemu.yml'
env:
IDF_VERSION: "v5.4"
QEMU_REPO: "https://github.com/espressif/qemu.git"
QEMU_BRANCH: "esp-develop"
jobs:
build-qemu:
name: Build Espressif QEMU
runs-on: ubuntu-latest
steps:
- name: Cache QEMU build
id: cache-qemu
uses: actions/cache@v4
with:
path: /opt/qemu-esp32
# Include date component so cache refreshes monthly when branch updates
key: qemu-esp32s3-${{ env.QEMU_BRANCH }}-v5
restore-keys: |
qemu-esp32s3-${{ env.QEMU_BRANCH }}-
- name: Install QEMU build dependencies
if: steps.cache-qemu.outputs.cache-hit != 'true'
run: |
sudo apt-get update
sudo apt-get install -y \
git build-essential ninja-build pkg-config \
libglib2.0-dev libpixman-1-dev libslirp-dev \
libgcrypt20-dev \
python3 python3-venv
- name: Clone and build Espressif QEMU
if: steps.cache-qemu.outputs.cache-hit != 'true'
run: |
git clone --depth 1 -b "$QEMU_BRANCH" "$QEMU_REPO" /tmp/qemu-esp
cd /tmp/qemu-esp
mkdir build && cd build
../configure \
--target-list=xtensa-softmmu \
--prefix=/opt/qemu-esp32 \
--enable-slirp \
--disable-werror
ninja -j$(nproc)
ninja install
- name: Verify QEMU binary
run: |
file_size() { stat -c%s "$1" 2>/dev/null || stat -f%z "$1" 2>/dev/null || wc -c < "$1"; }
/opt/qemu-esp32/bin/qemu-system-xtensa --version
echo "QEMU binary size: $(file_size /opt/qemu-esp32/bin/qemu-system-xtensa) bytes"
- name: Upload QEMU artifact
uses: actions/upload-artifact@v4
with:
name: qemu-esp32
path: /opt/qemu-esp32/
retention-days: 7
qemu-test:
name: QEMU Test (${{ matrix.nvs_config }})
needs: build-qemu
runs-on: ubuntu-latest
container:
image: espressif/idf:v5.4
strategy:
fail-fast: false
matrix:
nvs_config:
- default
- full-adr060
- edge-tier0
- edge-tier1
- tdm-3node
- boundary-max
- boundary-min
steps:
- uses: actions/checkout@v4
- name: Download QEMU artifact
uses: actions/download-artifact@v4
with:
name: qemu-esp32
path: /opt/qemu-esp32
- name: Make QEMU executable
run: chmod +x /opt/qemu-esp32/bin/qemu-system-xtensa
- name: Verify QEMU works
run: /opt/qemu-esp32/bin/qemu-system-xtensa --version
- name: Install Python dependencies
run: |
. $IDF_PATH/export.sh
pip install esptool esp-idf-nvs-partition-gen
- name: Set target ESP32-S3
working-directory: firmware/esp32-csi-node
run: |
. $IDF_PATH/export.sh
idf.py set-target esp32s3
- name: Build firmware (mock CSI mode)
working-directory: firmware/esp32-csi-node
run: |
. $IDF_PATH/export.sh
idf.py \
-D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.qemu" \
build
- name: Generate NVS matrix
run: |
. $IDF_PATH/export.sh
python3 scripts/generate_nvs_matrix.py \
--output-dir firmware/esp32-csi-node/build/nvs_matrix \
--only ${{ matrix.nvs_config }}
- name: Create merged flash image
working-directory: firmware/esp32-csi-node
run: |
. $IDF_PATH/export.sh
# Determine merge_bin arguments
OTA_ARGS=""
if [ -f build/ota_data_initial.bin ]; then
OTA_ARGS="0xf000 build/ota_data_initial.bin"
fi
python3 -m esptool --chip esp32s3 merge_bin \
-o build/qemu_flash.bin \
--flash_mode dio --flash_freq 80m --flash_size 8MB \
--fill-flash-size 8MB \
0x0 build/bootloader/bootloader.bin \
0x8000 build/partition_table/partition-table.bin \
$OTA_ARGS \
0x20000 build/esp32-csi-node.bin
file_size() { stat -c%s "$1" 2>/dev/null || stat -f%z "$1" 2>/dev/null || wc -c < "$1"; }
echo "Flash image size: $(file_size build/qemu_flash.bin) bytes"
- name: Inject NVS partition
if: matrix.nvs_config != 'default'
working-directory: firmware/esp32-csi-node
run: |
NVS_BIN="build/nvs_matrix/nvs_${{ matrix.nvs_config }}.bin"
if [ -f "$NVS_BIN" ]; then
file_size() { stat -c%s "$1" 2>/dev/null || stat -f%z "$1" 2>/dev/null || wc -c < "$1"; }
echo "Injecting NVS: $NVS_BIN ($(file_size "$NVS_BIN") bytes)"
dd if="$NVS_BIN" of=build/qemu_flash.bin \
bs=1 seek=$((0x9000)) conv=notrunc 2>/dev/null
else
echo "WARNING: NVS binary not found: $NVS_BIN"
fi
- name: Run QEMU smoke test
env:
QEMU_PATH: /opt/qemu-esp32/bin/qemu-system-xtensa
QEMU_TIMEOUT: "90"
run: |
echo "Starting QEMU (timeout: ${QEMU_TIMEOUT}s)..."
timeout "$QEMU_TIMEOUT" "$QEMU_PATH" \
-machine esp32s3 \
-nographic \
-drive file=firmware/esp32-csi-node/build/qemu_flash.bin,if=mtd,format=raw \
-serial mon:stdio \
-nic user,model=open_eth,net=10.0.2.0/24 \
-no-reboot \
2>&1 | tee firmware/esp32-csi-node/build/qemu_output.log || true
echo "QEMU finished. Log size: $(wc -l < firmware/esp32-csi-node/build/qemu_output.log) lines"
- name: Validate QEMU output
run: |
python3 scripts/validate_qemu_output.py \
firmware/esp32-csi-node/build/qemu_output.log
- name: Upload test logs
if: always()
uses: actions/upload-artifact@v4
with:
name: qemu-logs-${{ matrix.nvs_config }}
path: |
firmware/esp32-csi-node/build/qemu_output.log
firmware/esp32-csi-node/build/nvs_matrix/
retention-days: 14
fuzz-test:
name: Fuzz Testing (ADR-061 Layer 6)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install clang
run: |
sudo apt-get update
sudo apt-get install -y clang
- name: Build fuzz targets
working-directory: firmware/esp32-csi-node/test
run: make all CC=clang
- name: Run serialize fuzzer (60s)
working-directory: firmware/esp32-csi-node/test
run: make run_serialize FUZZ_DURATION=60 || echo "FUZZER_CRASH=serialize" >> "$GITHUB_ENV"
- name: Run edge enqueue fuzzer (60s)
working-directory: firmware/esp32-csi-node/test
run: make run_edge FUZZ_DURATION=60 || echo "FUZZER_CRASH=edge" >> "$GITHUB_ENV"
- name: Run NVS config fuzzer (60s)
working-directory: firmware/esp32-csi-node/test
run: make run_nvs FUZZ_DURATION=60 || echo "FUZZER_CRASH=nvs" >> "$GITHUB_ENV"
- name: Check for crashes
working-directory: firmware/esp32-csi-node/test
run: |
CRASHES=$(find . -type f \( -name "crash-*" -o -name "oom-*" -o -name "timeout-*" \) 2>/dev/null | wc -l)
echo "Crash artifacts found: $CRASHES"
if [ "$CRASHES" -gt 0 ] || [ -n "${FUZZER_CRASH:-}" ]; then
echo "::error::Fuzzer found $CRASHES crash/oom/timeout artifacts. FUZZER_CRASH=${FUZZER_CRASH:-none}"
ls -la crash-* oom-* timeout-* 2>/dev/null
exit 1
fi
- name: Upload fuzz artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: fuzz-crashes
path: |
firmware/esp32-csi-node/test/crash-*
firmware/esp32-csi-node/test/oom-*
firmware/esp32-csi-node/test/timeout-*
retention-days: 30
nvs-matrix-validate:
name: NVS Matrix Generation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install NVS generator
run: pip install esp-idf-nvs-partition-gen
- name: Generate all 14 NVS configs
run: |
python3 scripts/generate_nvs_matrix.py \
--output-dir build/nvs_matrix
- name: Verify all binaries generated
run: |
EXPECTED=14
ACTUAL=$(find build/nvs_matrix -type f -name "nvs_*.bin" 2>/dev/null | wc -l)
echo "Generated $ACTUAL / $EXPECTED NVS binaries"
ls -la build/nvs_matrix/
if [ "$ACTUAL" -lt "$EXPECTED" ]; then
echo "::error::Only $ACTUAL of $EXPECTED NVS binaries generated"
exit 1
fi
- name: Verify binary sizes
run: |
file_size() { stat -c%s "$1" 2>/dev/null || stat -f%z "$1" 2>/dev/null || wc -c < "$1"; }
for f in build/nvs_matrix/nvs_*.bin; do
SIZE=$(file_size "$f")
if [ "$SIZE" -ne 24576 ]; then
echo "::error::$f has unexpected size $SIZE (expected 24576)"
exit 1
fi
echo " OK: $(basename $f) ($SIZE bytes)"
done
# ---------------------------------------------------------------------------
# ADR-062: QEMU Swarm Configurator Test
#
# Runs a lightweight 3-node swarm (ci_matrix preset) under QEMU to validate
# multi-node orchestration, TDM slot coordination, and swarm-level health
# assertions. Uses the pre-built QEMU binary from the build-qemu job and the
# firmware built by qemu-test.
#
# The CI runner is non-root, so TAP bridge networking is unavailable.
# The orchestrator (qemu_swarm.py) detects this and falls back to SLIRP
# user-mode networking, which is sufficient for the ci_matrix preset.
# ---------------------------------------------------------------------------
swarm-test:
name: Swarm Test (ADR-062)
needs: [build-qemu]
runs-on: ubuntu-latest
container:
image: espressif/idf:v5.4
steps:
- uses: actions/checkout@v4
- name: Download QEMU artifact
uses: actions/download-artifact@v4
with:
name: qemu-esp32
path: /opt/qemu-esp32
- name: Make QEMU executable
run: chmod +x /opt/qemu-esp32/bin/qemu-system-xtensa
- name: Install Python dependencies
run: |
. $IDF_PATH/export.sh
pip install pyyaml esptool esp-idf-nvs-partition-gen
- name: Build firmware for swarm
working-directory: firmware/esp32-csi-node
run: |
. $IDF_PATH/export.sh
idf.py set-target esp32s3
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.qemu" build
python3 -m esptool --chip esp32s3 merge_bin \
-o build/qemu_flash.bin \
--flash_mode dio --flash_freq 80m --flash_size 8MB \
--fill-flash-size 8MB \
0x0 build/bootloader/bootloader.bin \
0x8000 build/partition_table/partition-table.bin \
0x20000 build/esp32-csi-node.bin
- name: Run swarm smoke test
run: |
. $IDF_PATH/export.sh
EXIT_CODE=0
python3 scripts/qemu_swarm.py --preset ci_matrix \
--qemu-path /opt/qemu-esp32/bin/qemu-system-xtensa \
--output-dir build/swarm-results || EXIT_CODE=$?
# Exit 0=PASS, 1=WARN (acceptable in CI without real hardware)
if [ "$EXIT_CODE" -gt 1 ]; then
echo "Swarm test failed with exit code $EXIT_CODE"
exit "$EXIT_CODE"
fi
timeout-minutes: 10
- name: Upload swarm results
if: always()
uses: actions/upload-artifact@v4
with:
name: swarm-results
path: |
build/swarm-results/
retention-days: 14
@@ -1,54 +0,0 @@
name: Fix-Marker Regression Guard
# Asserts that previously-shipped fixes are still present in the tree.
# Manifest: scripts/fix-markers.json Checker: scripts/check_fix_markers.py
# Run locally: python scripts/check_fix_markers.py (also --list / --json)
#
# This complements the heavyweight checks (firmware build, deterministic
# pipeline proof, witness bundle) with a fast per-PR "did someone revert a
# known fix?" gate — the CI analogue of the ruflo witness fix-marker system.
on:
push:
branches:
- main
- master
pull_request:
workflow_dispatch:
jobs:
fix-markers:
name: Verify fix markers
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Validate the manifest is well-formed JSON
run: python -c "import json; json.load(open('scripts/fix-markers.json')); print('manifest OK')"
- name: Check fix markers
run: python scripts/check_fix_markers.py
- name: Emit machine-readable result (for the run summary)
if: always()
run: |
python scripts/check_fix_markers.py --json > fix-markers-result.json || true
{
echo '### Fix-marker regression guard'
echo ''
echo '```'
python scripts/check_fix_markers.py || true
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload result artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: fix-markers-result
path: fix-markers-result.json
retention-days: 30
-110
View File
@@ -1,110 +0,0 @@
name: ADR-115 MQTT integration tests
# Runs the Mosquitto-broker-backed integration tests for ADR-115's MQTT
# publisher. These prove the publisher reaches a real broker, emits the
# expected HA-discovery topic shape, and honours --privacy-mode at the
# wire boundary (not just in unit-test logic).
#
# Default `cargo test --workspace` does not run these tests because they
# require a broker and pull rumqttc into the build. This workflow opts
# into both by setting --features mqtt and RUVIEW_RUN_INTEGRATION=1.
on:
pull_request:
paths:
- 'v2/crates/wifi-densepose-sensing-server/src/mqtt/**'
- 'v2/crates/wifi-densepose-sensing-server/tests/mqtt_integration.rs'
- 'v2/crates/wifi-densepose-sensing-server/Cargo.toml'
- '.github/workflows/mqtt-integration.yml'
push:
branches: [main]
paths:
- 'v2/crates/wifi-densepose-sensing-server/src/mqtt/**'
workflow_dispatch: {}
jobs:
mqtt-integration:
runs-on: ubuntu-latest
timeout-minutes: 20
# NB: we don't use a `services:` mosquitto container here because the
# eclipse-mosquitto:2.x image rejects anonymous connections by default
# and GH Actions `services` doesn't easily support mounting a custom
# config file. We start mosquitto manually in a step below with an
# inline `allow_anonymous true` config.
env:
RUVIEW_RUN_INTEGRATION: "1"
RUVIEW_TEST_MQTT_PORT: "11883"
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
steps:
- uses: actions/checkout@v4
- name: Install mosquitto + clients and start with allow_anonymous
run: |
sudo apt-get update -qq
sudo apt-get install -y mosquitto mosquitto-clients
sudo systemctl stop mosquitto || true
# Inline config: anon listener on 11883 only — no TLS, no auth,
# OK for CI because we test the wire shape, not security.
# Production deployments enable mTLS per ADR-115 §3.9.
cat > /tmp/mosquitto-ci.conf <<'EOF'
listener 11883
allow_anonymous true
persistence false
log_dest stdout
EOF
mosquitto -c /tmp/mosquitto-ci.conf -d
for i in {1..20}; do
if mosquitto_pub -h 127.0.0.1 -p 11883 -t healthcheck -m ok -q 0 2>/dev/null; then
echo "mosquitto reachable on 11883"; exit 0
fi
sleep 2
done
echo "mosquitto never became reachable" >&2
tail -50 /var/log/mosquitto/*.log 2>/dev/null || true
exit 1
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- name: Cache cargo registry + build
uses: Swatinem/rust-cache@v2
with:
workspaces: v2 -> target
- name: Validate HA Blueprints
run: |
python -m pip install --quiet pyyaml
python scripts/validate-ha-blueprints.py
- name: Verify unit tests still pass under --features mqtt
working-directory: v2
# `cargo test` accepts a single TESTNAME filter, so we run the
# whole --lib suite here. That gives us the full 410-test green
# bar under --features mqtt (which is more reassuring than
# filtering anyway).
run: >-
cargo test -p wifi-densepose-sensing-server
--features mqtt --no-default-features
--lib
--no-fail-fast
- name: Run integration tests against mosquitto
working-directory: v2
run: >-
cargo test -p wifi-densepose-sensing-server
--features mqtt --no-default-features
--test mqtt_integration
--no-fail-fast
-- --test-threads=1 --nocapture
- name: Dump broker logs on failure
if: failure()
run: |
docker ps -a
docker logs $(docker ps -aqf "ancestor=eclipse-mosquitto:2.0.18") || true
-69
View File
@@ -1,69 +0,0 @@
name: nvsim-server → ghcr.io
# Builds and publishes the nvsim-server Docker image to ghcr.io on:
# - push to main affecting nvsim-server or nvsim
# - tag push matching nvsim-server-v*
# - manual workflow_dispatch
#
# ADR-092 §6.2 + §9.4.
on:
push:
branches: [main]
paths:
- 'v2/crates/nvsim-server/**'
- 'v2/crates/nvsim/**'
- '.github/workflows/nvsim-server-docker.yml'
tags: ['nvsim-server-v*']
workflow_dispatch:
permissions:
contents: read
packages: write
jobs:
build-and-publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v6
with:
images: ghcr.io/ruvnet/nvsim-server
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,format=short
type=raw,value=latest,enable={{is_default_branch}}
- name: Build + push
uses: docker/build-push-action@v7
with:
context: v2
file: v2/crates/nvsim-server/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64
- name: Smoke-test the image
run: |
docker pull ghcr.io/ruvnet/nvsim-server:sha-${GITHUB_SHA::7} || \
docker pull ghcr.io/ruvnet/nvsim-server:latest
docker run --rm -d --name nvsim-test -p 7878:7878 \
ghcr.io/ruvnet/nvsim-server:latest
sleep 4
curl -fsS http://localhost:7878/api/health
docker stop nvsim-test
-286
View File
@@ -1,286 +0,0 @@
# ADR-117 P5 — cibuildwheel + PyPI publish workflow for `wifi-densepose`
#
# This workflow is **explicitly NOT** triggered on every push. It runs only on:
# - a maintainer-dispatched `workflow_dispatch`
# - a pushed tag matching `v*-pip` (e.g. `v2.0.0-pip`)
#
# The reason for the `-pip` tag suffix is that the repo already cuts
# `v0.X.Y-esp32` tags for firmware releases (see CLAUDE.md). The `-pip`
# suffix keeps the pip release schedule independent of the firmware
# release schedule.
#
# Sequencing on release day (per ADR-117 §7.3):
# 1. cut tag `v1.99.0-pip` → publishes the tombstone wheel first
# 2. cut tag `v2.0.0-pip` → publishes the PyO3 v2 wheel matrix
#
# Publishes via the `PYPI_API_TOKEN` GitHub Actions secret. The
# token-refresh runbook (GCP Secret Manager → gh secret set) lives in
# docs/integrations/pypi-release.md so KICS does not flag the
# secret name as a generic-secret literal in the workflow.
#
# Q3 (witness hash v2 — open in ADR-117 §11.3) MUST be resolved
# before the first v2.0.0 publish. When v2 lands, add a parallel
# step that verifies the v2 hash against the Rust pipeline.
name: pip-release
on:
workflow_dispatch:
inputs:
target:
description: "Which package to release"
required: true
type: choice
options:
- v2-wheels
- v1-99-tombstone
publish_to:
description: "Where to publish"
required: true
default: testpypi
type: choice
options:
- testpypi # dry-run target
- pypi # production
push:
tags:
- "v*-pip"
permissions:
contents: read
jobs:
# ────────────────────────────────────────────────────────────────
# v2.0.0 — cibuildwheel matrix (5 wheels + sdist)
# ────────────────────────────────────────────────────────────────
build-wheels:
name: Build ${{ matrix.os }} ${{ matrix.arch }}
if: |
github.event_name == 'workflow_dispatch' && inputs.target == 'v2-wheels' ||
startsWith(github.ref, 'refs/tags/v2.')
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
arch: x86_64
- os: ubuntu-latest
arch: aarch64
- os: macos-13 # x86_64 runner
arch: x86_64
- os: macos-14 # arm64 runner
arch: arm64
- os: windows-latest
arch: AMD64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
# Linux aarch64 needs QEMU for cross-build on x86_64 runners.
- name: Set up QEMU
if: matrix.os == 'ubuntu-latest' && matrix.arch == 'aarch64'
uses: docker/setup-qemu-action@v3
# ADR-117 §5.4: abi3-py310 — one binary per OS/arch covers all
# Python minor versions ≥ 3.10. Build only cp310 wheels.
- name: Build wheels (cibuildwheel)
uses: pypa/cibuildwheel@v2.21
env:
CIBW_BUILD: "cp310-*"
CIBW_ARCHS_LINUX: ${{ matrix.arch }}
CIBW_ARCHS_MACOS: ${{ matrix.arch }}
CIBW_ARCHS_WINDOWS: ${{ matrix.arch }}
CIBW_BUILD_FRONTEND: "build"
CIBW_BEFORE_BUILD: "pip install maturin>=1.7"
# The PyO3 sdist landing depends on the cargo/Rust toolchain
# being present. cibuildwheel images carry rustup on Linux
# but we also pin a known-good version for reproducibility.
CIBW_BEFORE_ALL_LINUX: "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.82"
CIBW_ENVIRONMENT_LINUX: 'PATH="$HOME/.cargo/bin:$PATH"'
# Smoke-test every built wheel before accepting it. Catches
# the case where the wheel imports but the compiled symbols
# are missing.
CIBW_TEST_REQUIRES: "pytest>=8.0"
CIBW_TEST_COMMAND: 'python -c "import wifi_densepose; assert wifi_densepose.hello() == \"ok\"; print(wifi_densepose.__build_features__)"'
with:
package-dir: python
output-dir: wheelhouse
- uses: actions/upload-artifact@v4
with:
name: wheels-${{ matrix.os }}-${{ matrix.arch }}
path: wheelhouse/*.whl
if-no-files-found: error
build-sdist:
name: Build v2 sdist
if: |
github.event_name == 'workflow_dispatch' && inputs.target == 'v2-wheels' ||
startsWith(github.ref, 'refs/tags/v2.')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install maturin
run: pip install maturin>=1.7
- name: Build sdist
working-directory: python
run: maturin sdist --out ../sdist
- uses: actions/upload-artifact@v4
with:
name: sdist
path: sdist/*.tar.gz
if-no-files-found: error
# ────────────────────────────────────────────────────────────────
# v1.99.0 — tombstone wheel (pure Python, single sdist + wheel)
# ────────────────────────────────────────────────────────────────
build-tombstone:
name: Build v1.99.0 tombstone
if: |
github.event_name == 'workflow_dispatch' && inputs.target == 'v1-99-tombstone' ||
startsWith(github.ref, 'refs/tags/v1.99')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install build backend
run: python -m pip install --upgrade pip build>=1.2
- name: Build sdist + wheel
working-directory: python/tombstone
run: python -m build --outdir ../../tombstone-dist
# Inspect what was actually built — the previous v1.99.0-pip run
# showed an `import wifi_densepose` that returned cleanly instead
# of raising, even though build logs said `adding 'wifi_densepose/__init__.py'`.
# Print the wheel manifest + the __init__.py content so any
# future regression is debuggable from the run log alone.
- name: Inspect wheel contents
run: |
set -e
WHL=tombstone-dist/wifi_densepose-1.99.0-py3-none-any.whl
echo "--- wheel listing ---"
python -m zipfile -l "$WHL"
echo "--- wifi_densepose/__init__.py inside the wheel ---"
python -m zipfile -e "$WHL" /tmp/tomb-inspect
cat /tmp/tomb-inspect/wifi_densepose/__init__.py
echo "--- size in bytes ---"
wc -c /tmp/tomb-inspect/wifi_densepose/__init__.py
# Smoke-test in an ISOLATED venv. The previous run's failure
# mode was that the ubuntu-latest runner's system `python` had
# site-packages picking up something other than the user-installed
# wheel, so the import resolved to a different module. A clean
# venv removes any ambiguity about which wifi_densepose is loaded.
- name: Smoke-test tombstone in isolated venv
run: |
set -e
# Copy the wheel to /tmp BEFORE entering the venv — we must
# cd OUT of the repo root because the repo contains a
# `wifi_densepose/` directory left over from the legacy v1
# source. Python puts cwd at sys.path[0], so an import from
# the repo root would resolve to the legacy directory and
# bypass the freshly-installed wheel entirely (this was the
# silent failure mode of the previous two run attempts).
cp tombstone-dist/wifi_densepose-1.99.0-py3-none-any.whl /tmp/
python -m venv /tmp/smoke-venv
/tmp/smoke-venv/bin/python -m pip install --upgrade pip
/tmp/smoke-venv/bin/python -m pip install /tmp/wifi_densepose-1.99.0-py3-none-any.whl
cd /tmp # away from the repo root's stray wifi_densepose/
/tmp/smoke-venv/bin/python -c "import importlib.util as u; s = u.find_spec('wifi_densepose'); print('Resolved to:', s.origin); print('--- file content ---'); print(open(s.origin).read())"
set +e
/tmp/smoke-venv/bin/python -c "import wifi_densepose" 2> import-output.txt
rc=$?
set -e
if [ "$rc" -eq 0 ]; then
echo "ERROR: tombstone import succeeded — should have raised ImportError"
exit 1
fi
if ! grep -q "github.com/ruvnet/RuView" import-output.txt; then
echo "ERROR: tombstone ImportError missing migration URL"
cat import-output.txt
exit 1
fi
echo "Tombstone wheel correctly raises ImportError with migration URL."
- uses: actions/upload-artifact@v4
with:
name: tombstone
path: tombstone-dist/*
if-no-files-found: error
# ────────────────────────────────────────────────────────────────
# Publish — gated by manual dispatch OR by the tag form
# ────────────────────────────────────────────────────────────────
publish-v2:
name: Publish v2 wheels
needs: [build-wheels, build-sdist]
if: |
always() &&
needs.build-wheels.result == 'success' &&
needs.build-sdist.result == 'success' &&
(
github.event_name == 'workflow_dispatch' && inputs.target == 'v2-wheels' ||
startsWith(github.ref, 'refs/tags/v2.')
)
runs-on: ubuntu-latest
steps:
- name: Gather all artifacts into dist/
uses: actions/download-artifact@v4
with:
path: dist-staging
- name: Flatten artifacts
run: |
mkdir -p dist
find dist-staging -type f \( -name '*.whl' -o -name '*.tar.gz' \) -exec cp -v {} dist/ \;
ls -lh dist/
- name: Publish to TestPyPI (dry-run target)
if: github.event_name == 'workflow_dispatch' && inputs.publish_to == 'testpypi'
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
password: ${{ secrets.PYPI_API_TOKEN }}
packages-dir: dist
skip-existing: true
- name: Publish to PyPI
if: |
startsWith(github.ref, 'refs/tags/v2.') ||
(github.event_name == 'workflow_dispatch' && inputs.publish_to == 'pypi')
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
packages-dir: dist
publish-tombstone:
name: Publish v1.99 tombstone
needs: [build-tombstone]
if: |
always() &&
needs.build-tombstone.result == 'success' &&
(
github.event_name == 'workflow_dispatch' && inputs.target == 'v1-99-tombstone' ||
startsWith(github.ref, 'refs/tags/v1.99')
)
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: tombstone
path: dist
- name: Publish to TestPyPI (dry-run target)
if: github.event_name == 'workflow_dispatch' && inputs.publish_to == 'testpypi'
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
password: ${{ secrets.PYPI_API_TOKEN }}
packages-dir: dist
skip-existing: true
- name: Publish to PyPI
if: |
startsWith(github.ref, 'refs/tags/v1.99') ||
(github.event_name == 'workflow_dispatch' && inputs.publish_to == 'pypi')
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
packages-dir: dist
-74
View File
@@ -1,74 +0,0 @@
name: Point Cloud Viewer → GitHub Pages
# Publishes the live 3D point cloud viewer to gh-pages/pointcloud/.
# The viewer defaults to a synthetic in-browser demo; users can append
# ?backend=<url> or ?backend=auto to point it at a real ruview-pointcloud
# server (CORS-permitting host required). See ADR-094.
#
# Uses keep_files: true to preserve the existing observatory/, pose-fusion/,
# nvsim/, and root index.html demos already on gh-pages.
on:
push:
branches: [main]
paths:
- 'v2/crates/wifi-densepose-pointcloud/src/viewer.html'
- '.github/workflows/pointcloud-pages.yml'
workflow_dispatch:
permissions:
contents: write
concurrency:
group: pointcloud-pages
cancel-in-progress: true
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout main
uses: actions/checkout@v4
- name: Stage viewer for Pages
run: |
mkdir -p _site/pointcloud
cp v2/crates/wifi-densepose-pointcloud/src/viewer.html _site/pointcloud/index.html
# Drop a tiny README so direct browsers of the directory get context.
cat > _site/pointcloud/README.md <<'EOF'
# RuView — Live 3D Point Cloud Viewer
Hosted at: https://ruvnet.github.io/RuView/pointcloud/
## Modes
- Default — synthetic in-browser demo (no backend, no network calls).
- `?backend=auto` — fetch from `/api/splats` on the same origin
(only works when the viewer is served by `ruview-pointcloud serve`).
- `?backend=<url>` — fetch from `<url>/api/splats`. The intended
local-ESP32 use is `?backend=http://127.0.0.1:9880`: run
`ruview-pointcloud serve --bind 127.0.0.1:9880` on the same
machine with your ESP32 streaming CSI to UDP port 3333, then
visit the URL above. The local server's CorsLayer permits
requests from `https://ruvnet.github.io`, and modern browsers
permit HTTPS→127.0.0.1 mixed-content as a trustworthy origin.
The "📡 Connect ESP32" button in the viewer prompts for this
URL and persists it in localStorage.
- `?live=1` — require a live backend; show an offline message instead
of falling back to the synthetic demo.
See ADR-094 for the deployment design.
EOF
- name: Deploy to gh-pages/pointcloud/
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./_site/pointcloud
destination_dir: pointcloud
# CRITICAL: preserves observatory/, pose-fusion/, nvsim/, and root
# index.html already on gh-pages.
keep_files: true
commit_message: 'deploy(pointcloud): ${{ github.sha }}'
user_name: 'github-actions[bot]'
user_email: 'github-actions[bot]@users.noreply.github.com'
-149
View File
@@ -1,149 +0,0 @@
name: ruview-swarm CI guard
# Dedicated guard for the ADR-148 drone swarm crate (`v2/crates/ruview-swarm`).
# The main ci.yml runs `cargo test --workspace --no-default-features`, which
# only exercises ruview-swarm's DEFAULT feature set. This guard additionally:
# - tests every feature combination (train / ruflo+itar / full)
# - fails on ANY clippy warning in the crate's own code (--no-deps)
# - asserts the ITAR + publish guards stay in place (USML Cat VIII(h)(12))
# - builds the GPU training binary under the `train` feature
#
# Path-scoped so it only runs when the crate or this workflow changes.
on:
push:
branches: [ main, 'feat/*' ]
paths:
- 'v2/crates/ruview-swarm/**'
- '.github/workflows/ruview-swarm-ci.yml'
pull_request:
paths:
- 'v2/crates/ruview-swarm/**'
- '.github/workflows/ruview-swarm-ci.yml'
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
jobs:
# ── Feature-matrix tests ─────────────────────────────────────────────────
tests:
name: tests (${{ matrix.features.label }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
features:
- { label: 'default', flags: '--no-default-features' }
- { label: 'train', flags: '--features train' }
- { label: 'ruflo+itar', flags: '--features ruflo,itar-unrestricted' }
- { label: 'full+train', flags: '--features full,train' }
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
v2/target
key: ${{ runner.os }}-ruview-swarm-${{ hashFiles('v2/Cargo.lock') }}
restore-keys: ${{ runner.os }}-ruview-swarm-
- name: cargo test -p ruview-swarm ${{ matrix.features.flags }}
working-directory: v2
run: cargo test -p ruview-swarm ${{ matrix.features.flags }} --lib
# ── Clippy: zero warnings in the crate's own code ────────────────────────
clippy:
name: clippy (-D warnings, --no-deps)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# v2/rust-toolchain.toml pins channel "1.89" with profile "minimal" (no
# clippy). dtolnay@stable installs clippy on the floating "stable"
# toolchain, but the override makes cargo use the separate "1.89"
# toolchain — so `cargo clippy` errors "cargo-clippy is not installed for
# 1.89". Install clippy on the pinned toolchain that cargo actually uses.
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.89"
components: clippy
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
v2/target
key: ${{ runner.os }}-ruview-swarm-clippy-${{ hashFiles('v2/Cargo.lock') }}
restore-keys: ${{ runner.os }}-ruview-swarm-clippy-
# --no-deps confines linting to ruview-swarm's own source, so pre-existing
# warnings in dependency crates don't gate this PR.
- name: clippy (default)
working-directory: v2
run: cargo clippy -p ruview-swarm --no-default-features --no-deps -- -D warnings
- name: clippy (full,train)
working-directory: v2
run: cargo clippy -p ruview-swarm --features full,train --no-deps -- -D warnings
# ── Build the GPU training binary (train feature) ────────────────────────
train-bin:
name: build train_marl bin
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
v2/target
key: ${{ runner.os }}-ruview-swarm-bin-${{ hashFiles('v2/Cargo.lock') }}
restore-keys: ${{ runner.os }}-ruview-swarm-bin-
- name: cargo build --bin train_marl --features train
working-directory: v2
run: cargo build -p ruview-swarm --features train --bin train_marl
- name: train_marl is excluded from the default build
working-directory: v2
run: |
# The training binary requires the `train` feature; a default `--bins`
# build must NOT produce it (keeps default/CI builds light + Candle-free).
# Remove any prior artifact first so this checks what the DEFAULT build
# produces, not a leftover from the train-feature build above.
rm -f target/debug/train_marl
cargo build -p ruview-swarm --no-default-features --bins
if [ -f target/debug/train_marl ]; then
echo "ERROR: train_marl built without the 'train' feature" >&2
exit 1
fi
echo "OK: train_marl correctly gated behind the 'train' feature"
# ── ITAR + publish guards ────────────────────────────────────────────────
export-control-guard:
name: ITAR / publish guard
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: publish = false is present (no accidental crates.io publish)
run: |
CARGO=v2/crates/ruview-swarm/Cargo.toml
if ! grep -qE '^\s*publish\s*=\s*false' "$CARGO"; then
echo "ERROR: ruview-swarm Cargo.toml must keep 'publish = false' until" >&2
echo " PR merge + dependency publish + ITAR export sign-off." >&2
exit 1
fi
echo "OK: publish = false present"
- name: default feature set does NOT enable itar-unrestricted
run: |
CARGO=v2/crates/ruview-swarm/Cargo.toml
# USML Cat VIII(h)(12): swarming coordination must be opt-in, never default.
DEFAULT_LINE=$(grep -E '^\s*default\s*=' "$CARGO" || true)
echo "default = $DEFAULT_LINE"
if echo "$DEFAULT_LINE" | grep -q 'itar-unrestricted'; then
echo "ERROR: 'itar-unrestricted' must NOT be in the default feature set" >&2
exit 1
fi
echo "OK: ITAR-gated coordination features are opt-in, not default"
+30 -92
View File
@@ -2,7 +2,7 @@ name: Security Scanning
on:
push:
branches: [ main, develop, 'feat/*' ]
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
schedule:
@@ -18,27 +18,23 @@ jobs:
sast:
name: Static Application Security Testing
runs-on: ubuntu-latest
continue-on-error: true # third-party scanners are flaky / SARIF uploads can 403; don't gate the PR
permissions:
security-events: write
actions: read
contents: read
steps:
- name: Checkout code
continue-on-error: true
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
continue-on-error: true
uses: actions/setup-python@v6
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: Install dependencies
continue-on-error: true
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
@@ -50,15 +46,13 @@ jobs:
continue-on-error: true
- name: Upload Bandit results to GitHub Security
continue-on-error: true
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: bandit-results.sarif
category: bandit
- name: Run Semgrep security scan
continue-on-error: true
uses: returntocorp/semgrep-action@v1
with:
config: >-
@@ -76,8 +70,7 @@ jobs:
continue-on-error: true
- name: Upload Semgrep results to GitHub Security
continue-on-error: true
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: semgrep.sarif
@@ -87,25 +80,21 @@ jobs:
dependency-scan:
name: Dependency Vulnerability Scan
runs-on: ubuntu-latest
continue-on-error: true # third-party scanners are flaky / SARIF uploads can 403; don't gate the PR
permissions:
security-events: write
actions: read
contents: read
steps:
- name: Checkout code
continue-on-error: true
uses: actions/checkout@v4
- name: Set up Python
continue-on-error: true
uses: actions/setup-python@v6
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: Install dependencies
continue-on-error: true
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
@@ -122,7 +111,7 @@ jobs:
continue-on-error: true
- name: Run Snyk vulnerability scan
uses: snyk/actions/python@9adf32b1121593767fc3c057af55b55db032dc04 # v1.0.0
uses: snyk/actions/python@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
@@ -130,16 +119,14 @@ jobs:
continue-on-error: true
- name: Upload Snyk results to GitHub Security
continue-on-error: true
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: snyk-results.sarif
category: snyk
- name: Upload vulnerability reports
continue-on-error: true
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
if: always()
with:
name: vulnerability-reports
@@ -152,7 +139,6 @@ jobs:
container-scan:
name: Container Security Scan
runs-on: ubuntu-latest
continue-on-error: true # third-party scanners are flaky / SARIF uploads can 403; don't gate the PR
needs: []
if: github.event_name == 'push' || github.event_name == 'schedule'
permissions:
@@ -161,16 +147,13 @@ jobs:
contents: read
steps:
- name: Checkout code
continue-on-error: true
uses: actions/checkout@v4
- name: Set up Docker Buildx
continue-on-error: true
uses: docker/setup-buildx-action@v3
- name: Build Docker image for scanning
continue-on-error: true
uses: docker/build-push-action@v7
uses: docker/build-push-action@v5
with:
context: .
target: production
@@ -180,24 +163,21 @@ jobs:
cache-to: type=gha,mode=max
- name: Run Trivy vulnerability scanner
continue-on-error: true
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
uses: aquasecurity/trivy-action@master
with:
image-ref: 'wifi-densepose:scan'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy results to GitHub Security
continue-on-error: true
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'
category: trivy
- name: Run Grype vulnerability scanner
continue-on-error: true
uses: anchore/scan-action@v7
uses: anchore/scan-action@v3
id: grype-scan
with:
image: 'wifi-densepose:scan'
@@ -206,15 +186,13 @@ jobs:
output-format: sarif
- name: Upload Grype results to GitHub Security
continue-on-error: true
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: ${{ steps.grype-scan.outputs.sarif }}
category: grype
- name: Run Docker Scout
continue-on-error: true
uses: docker/scout-action@v1
if: always()
with:
@@ -224,8 +202,7 @@ jobs:
summary: true
- name: Upload Docker Scout results
continue-on-error: true
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: scout-results.sarif
@@ -235,19 +212,16 @@ jobs:
iac-scan:
name: Infrastructure Security Scan
runs-on: ubuntu-latest
continue-on-error: true # third-party scanners are flaky / SARIF uploads can 403; don't gate the PR
permissions:
security-events: write
actions: read
contents: read
steps:
- name: Checkout code
continue-on-error: true
uses: actions/checkout@v4
- name: Run Checkov IaC scan
continue-on-error: true
uses: bridgecrewio/checkov-action@99bb2caf247dfd9f03cf984373bc6043d4e32ebf # v12.1347.0
uses: bridgecrewio/checkov-action@master
with:
directory: .
framework: kubernetes,dockerfile,terraform,ansible
@@ -257,16 +231,14 @@ jobs:
soft_fail: true
- name: Upload Checkov results to GitHub Security
continue-on-error: true
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: checkov-results.sarif
category: checkov
- name: Run Terrascan IaC scan
continue-on-error: true
uses: tenable/terrascan-action@3a6e87da8e244513bd77b631e624552643f794c6 # v1.4.1
uses: tenable/terrascan-action@main
with:
iac_type: 'k8s'
iac_version: 'v1'
@@ -275,8 +247,7 @@ jobs:
sarif_upload: true
- name: Run KICS IaC scan
continue-on-error: true
uses: checkmarx/kics-github-action@05aa5eb70eede1355220f4ca5238d96b397e30a6 # v2.1.20
uses: checkmarx/kics-github-action@master
with:
path: '.'
output_path: kics-results
@@ -285,8 +256,7 @@ jobs:
exclude_queries: 'a7ef1e8c-fbf8-4ac1-b8c7-2c3b0e6c6c6c'
- name: Upload KICS results to GitHub Security
continue-on-error: true
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: kics-results/results.sarif
@@ -296,21 +266,18 @@ jobs:
secret-scan:
name: Secret Scanning
runs-on: ubuntu-latest
continue-on-error: true # third-party scanners are flaky / SARIF uploads can 403; don't gate the PR
permissions:
security-events: write
actions: read
contents: read
steps:
- name: Checkout code
continue-on-error: true
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run TruffleHog secret scan
continue-on-error: true
uses: trufflesecurity/trufflehog@17456f8c7d042d8c82c9a8ca9e937231f9f42e26 # v3.95.2
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: main
@@ -318,7 +285,6 @@ jobs:
extra_args: --debug --only-verified
- name: Run GitLeaks secret scan
continue-on-error: true
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -335,35 +301,29 @@ jobs:
license-scan:
name: License Compliance Scan
runs-on: ubuntu-latest
continue-on-error: true # third-party scanners are flaky / SARIF uploads can 403; don't gate the PR
steps:
- name: Checkout code
continue-on-error: true
uses: actions/checkout@v4
- name: Set up Python
continue-on-error: true
uses: actions/setup-python@v6
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: Install dependencies
continue-on-error: true
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pip-licenses licensecheck
- name: Run license check
continue-on-error: true
run: |
pip-licenses --format=json --output-file=licenses.json
licensecheck --zero
- name: Upload license report
continue-on-error: true
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: license-report
path: licenses.json
@@ -372,14 +332,11 @@ jobs:
compliance-check:
name: Security Policy Compliance
runs-on: ubuntu-latest
continue-on-error: true # third-party scanners are flaky / SARIF uploads can 403; don't gate the PR
steps:
- name: Checkout code
continue-on-error: true
uses: actions/checkout@v4
- name: Check security policy files
continue-on-error: true
run: |
# Check for required security files
files=("SECURITY.md" ".github/SECURITY.md" "docs/SECURITY.md")
@@ -397,44 +354,31 @@ jobs:
fi
- name: Check for security headers in code
continue-on-error: true
run: |
# Check for security-related configurations
grep -r "X-Frame-Options\|X-Content-Type-Options\|X-XSS-Protection\|Content-Security-Policy" src/ || echo "⚠️ Consider adding security headers"
- name: Validate Kubernetes security contexts
continue-on-error: true
run: |
# Check for security contexts in Kubernetes manifests
if [[ -d "k8s" ]]; then
if find k8s/ -name "*.yaml" -exec grep -l "securityContext" {} \; | wc -l | grep -q "^0$"; then
echo "⚠️ No security contexts found in Kubernetes manifests"
else
echo "✅ Security contexts found in Kubernetes manifests"
fi
if find k8s/ -name "*.yaml" -exec grep -l "securityContext" {} \; | wc -l | grep -q "^0$"; then
echo "❌ No security contexts found in Kubernetes manifests"
exit 1
else
echo "️ No k8s/ directory found — skipping Kubernetes security context check"
echo "✅ Security contexts found in Kubernetes manifests"
fi
# Notification and reporting
security-report:
name: Security Report
runs-on: ubuntu-latest
continue-on-error: true # third-party scanners are flaky / SARIF uploads can 403; don't gate the PR
needs: [sast, dependency-scan, container-scan, iac-scan, secret-scan, license-scan, compliance-check]
if: always()
# Promote secret to env-scope so the gating `if:` on the Slack-notify
# step below is parseable (GitHub Actions rejects `secrets.X` in
# step-level `if:` expressions).
env:
SECURITY_SLACK_WEBHOOK_URL: ${{ secrets.SECURITY_SLACK_WEBHOOK_URL }}
steps:
- name: Download all artifacts
continue-on-error: true
uses: actions/download-artifact@v4
uses: actions/download-artifact@v3
- name: Generate security summary
continue-on-error: true
run: |
echo "# Security Scan Summary" > security-summary.md
echo "" >> security-summary.md
@@ -450,18 +394,13 @@ jobs:
echo "Generated on: $(date)" >> security-summary.md
- name: Upload security summary
continue-on-error: true
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: security-summary
path: security-summary.md
# GitHub Actions does not allow `secrets.X` in step-level `if:` —
# use env.X instead. Inherits SECURITY_SLACK_WEBHOOK_URL from the
# job-level env block (added below).
- name: Notify security team on critical findings
continue-on-error: true
if: ${{ env.SECURITY_SLACK_WEBHOOK_URL != '' && (needs.sast.result == 'failure' || needs.dependency-scan.result == 'failure' || needs.container-scan.result == 'failure') }}
if: needs.sast.result == 'failure' || needs.dependency-scan.result == 'failure' || needs.container-scan.result == 'failure'
uses: 8398a7/action-slack@v3
with:
status: failure
@@ -473,10 +412,9 @@ jobs:
Workflow: ${{ github.workflow }}
Please review the security scan results immediately.
env:
SLACK_WEBHOOK_URL: ${{ env.SECURITY_SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_URL: ${{ secrets.SECURITY_SLACK_WEBHOOK_URL }}
- name: Create security issue on critical findings
continue-on-error: true
if: needs.sast.result == 'failure' || needs.dependency-scan.result == 'failure'
uses: actions/github-script@v6
with:
-181
View File
@@ -1,181 +0,0 @@
name: wifi-densepose sensing-server → Docker Hub + ghcr.io
# Build + publish the `wifi-densepose` sensing-server image to both Docker Hub
# (`ruvnet/wifi-densepose`) and ghcr.io (`ghcr.io/ruvnet/wifi-densepose`) on:
# - push to main affecting the Dockerfile, the server crate, the UI assets,
# or this workflow itself,
# - tag push matching v* (release builds),
# - manual workflow_dispatch.
#
# Closes #520 and #514: the stale `:latest` is rebuilt and pushed automatically
# whenever the surface that produces it changes, and the Dockerfile fails the
# build if the observatory/pose-fusion UI assets ever go missing again.
#
# Secrets:
# DOCKERHUB_USERNAME — `ruvnet` (Docker Hub login name)
# DOCKERHUB_TOKEN — Docker Hub access token with read/write/delete scope
# (ghcr.io uses the workflow's GITHUB_TOKEN — no secret needed.)
on:
push:
branches: [main]
paths:
- 'docker/Dockerfile.rust'
- 'docker/docker-entrypoint.sh'
- 'v2/crates/wifi-densepose-sensing-server/**'
- 'v2/crates/wifi-densepose-signal/**'
- 'v2/crates/wifi-densepose-vitals/**'
- 'v2/crates/wifi-densepose-wifiscan/**'
- 'v2/crates/wifi-densepose-bfld/**'
- 'v2/crates/cog-ha-matter/**'
- 'v2/Cargo.toml'
- 'v2/Cargo.lock'
- 'ui/**'
- '.github/workflows/sensing-server-docker.yml'
tags: ['v*']
workflow_dispatch: {}
permissions:
contents: read
packages: write
concurrency:
group: sensing-server-docker-${{ github.ref }}
cancel-in-progress: true
jobs:
build-and-publish:
name: build · push · smoke-test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
# QEMU is required so the amd64 GitHub runner can cross-build the
# linux/arm64 layer below (Dockerfile.rust is arch-agnostic — no `--target`
# flag — so buildx + QEMU is all that's needed; arm64 builds are emulated
# by the runner, not built on a separate arm64 host).
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
# Bypassing docker/login-action@v3: the action kept emitting
# "malformed HTTP Authorization header" against a known-good
# dckr_pat_* token (verified by direct curl against the Hub API).
# `docker login --password-stdin` is the documented credential
# path and avoids whatever encoding step the action injects.
env:
DH_USER: ${{ secrets.DOCKERHUB_USERNAME }}
DH_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
run: |
printf '%s' "$DH_TOKEN" | docker login docker.io -u "$DH_USER" --password-stdin
- name: Log in to ghcr.io
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Compute tags
id: meta
uses: docker/metadata-action@v6
with:
images: |
docker.io/ruvnet/wifi-densepose
ghcr.io/ruvnet/wifi-densepose
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,format=short
type=raw,value=latest,enable={{is_default_branch}}
- name: Build + push
id: build
uses: docker/build-push-action@v7
with:
context: .
file: docker/Dockerfile.rust
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# README badge advertises `amd64 + arm64`, and #547 promised multi-arch
# as part of the docker publish refresh; arm64 was never actually wired
# in, so Apple Silicon Macs hit `no matching manifest for linux/arm64/v8`
# on `docker pull ruvnet/wifi-densepose:latest` (#136, #625). Build both.
platforms: linux/amd64,linux/arm64
# ---------------------------------------------------------------------
# Smoke-test the freshly-pushed image:
# 1. UI assets that closed #520 are inside `/app/ui` (the Dockerfile's
# RUN guard catches missing ones at build time, this re-checks the
# pushed artifact post-hoc as belt-and-braces).
# 2. /health is up.
# 3. /api/v1/info returns 200 with no auth (LAN-mode default).
# 4. With RUVIEW_API_TOKEN set, /api/v1/info returns 401 without a
# Bearer header, 200 with the correct one (the #443 auth middleware).
# ---------------------------------------------------------------------
- name: Smoke-test image assets + LAN-mode HTTP
run: |
set -euo pipefail
IMAGE="ghcr.io/ruvnet/wifi-densepose:sha-${GITHUB_SHA::7}"
docker pull "$IMAGE"
docker run --rm "$IMAGE" sh -c \
'ls /app/ui/observatory.html /app/ui/pose-fusion.html /app/ui/index.html /app/ui/viz.html >/dev/null'
docker run --rm "$IMAGE" sh -c 'ls -d /app/ui/observatory /app/ui/pose-fusion >/dev/null'
docker run -d --name sm -p 3000:3000 -e CSI_SOURCE=simulated "$IMAGE"
# Wait up to 30 s for /health.
for _ in $(seq 1 30); do
if curl -fsS http://127.0.0.1:3000/health >/dev/null 2>&1; then break; fi
sleep 1
done
curl -fsS http://127.0.0.1:3000/health
curl -fsS http://127.0.0.1:3000/api/v1/info >/dev/null
curl -fsS http://127.0.0.1:3000/ui/observatory.html >/dev/null
curl -fsS http://127.0.0.1:3000/ui/pose-fusion.html >/dev/null
docker stop sm
- name: Smoke-test the bearer-token auth path
run: |
set -euo pipefail
IMAGE="ghcr.io/ruvnet/wifi-densepose:sha-${GITHUB_SHA::7}"
docker run -d --name auth \
-p 3000:3000 \
-e CSI_SOURCE=simulated \
-e RUVIEW_API_TOKEN=smoke-test-token-do-not-use \
"$IMAGE"
for _ in $(seq 1 30); do
if curl -fsS http://127.0.0.1:3000/health >/dev/null 2>&1; then break; fi
sleep 1
done
# /health stays unauthenticated.
curl -fsS http://127.0.0.1:3000/health >/dev/null
# /api/v1/info without a bearer → 401.
code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/api/v1/info)
test "$code" = "401" || { echo "expected 401, got $code"; exit 1; }
# Wrong bearer → 401.
code=$(curl -s -o /dev/null -w '%{http_code}' -H 'Authorization: Bearer wrong' http://127.0.0.1:3000/api/v1/info)
test "$code" = "401" || { echo "expected 401 (wrong token), got $code"; exit 1; }
# Correct bearer → 200.
curl -fsS -H 'Authorization: Bearer smoke-test-token-do-not-use' http://127.0.0.1:3000/api/v1/info >/dev/null
docker stop auth
- name: Summary
if: always()
run: |
{
echo "## sensing-server image published"
echo
echo "Tags:"
echo '```'
echo "${{ steps.meta.outputs.tags }}"
echo '```'
echo
echo "Closes #520 (missing observatory/pose-fusion UI assets) and #514 (stale `:latest` for the v0.6+ packet format)."
echo "The Dockerfile fails the build if those UI assets ever disappear again, and this workflow rebuilds + pushes automatically on every change to the surface."
} >> "$GITHUB_STEP_SUMMARY"
-70
View File
@@ -1,70 +0,0 @@
name: three.js demos → GitHub Pages
# Publishes the ADR-097 three.js demos under gh-pages/three.js/.
# Uses keep_files: true so the existing observatory/, pose-fusion/,
# pointcloud/, nvsim/, and root index.html demos are preserved.
#
# Demos 04 and 05 require a Mixamo "X Bot.fbx" placed in assets/.
# That file is intentionally gitignored (license boundary), so this
# workflow does NOT ship it. Demos 01-03 work standalone; the index
# page documents the FBX requirement honestly.
on:
push:
branches: [main]
paths:
- 'examples/three.js/**'
- '.github/workflows/threejs-pages.yml'
workflow_dispatch:
permissions:
contents: write
concurrency:
group: threejs-pages
cancel-in-progress: true
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout main
uses: actions/checkout@v4
- name: Stage demos for Pages
run: |
mkdir -p _site/three.js
# Copy everything except the local Python server (CI doesn't need it)
# and any stray scratch screenshots.
cp -r examples/three.js/demos _site/three.js/demos
cp -r examples/three.js/screenshots _site/three.js/screenshots
cp examples/three.js/README.md _site/three.js/README.md
# An index.html that lists the 5 demos with the FBX caveat.
cp examples/three.js/index.html _site/three.js/index.html
# Mixamo FBX is gitignored — assets dir won't exist in CI.
# Drop an empty placeholder so the relative path 'assets/' resolves
# to a directory listing (404 on missing file) instead of an opaque
# network error. Browsers showing the 404 path makes the failure
# visible to anyone trying demos 04/05 without their own FBX.
mkdir -p _site/three.js/assets
cat > _site/three.js/assets/README.txt <<'EOF'
The Mixamo "X Bot.fbx" required by demos 04-skinned-fbx.html and
05-skinned-realtime.html is intentionally not redistributed here.
Download your own from https://mixamo.com (FBX Binary, T-Pose,
Without Skin) and place it here as "X Bot.fbx" if you want to
run those demos locally. See examples/three.js/README.md in the
repo for context.
EOF
echo "Staged contents:"
ls -R _site/three.js/ | head -30
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: _site
# Critical: preserve observatory/, pose-fusion/, pointcloud/, nvsim/
# and the root index.html already on gh-pages.
keep_files: true
commit_message: 'three.js demos: ${{ github.event.head_commit.message }}'
-67
View File
@@ -1,67 +0,0 @@
name: Update vendor submodules
on:
schedule:
- cron: '0 */6 * * *' # Every 6 hours
workflow_dispatch: # Manual trigger
permissions:
contents: write
pull-requests: write
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
# Identity must be set BEFORE any operation that can create a commit.
# `git submodule update --remote --merge` used to fail here with
# "Committer identity unknown" because the merge inside vendor/ruvector
# needs an author when the pinned commit isn't a fast-forward of upstream.
- name: Configure git identity
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
# Use a plain `--remote` checkout (detached HEAD at each submodule's
# configured `branch` tip from .gitmodules) rather than `--merge`. We only
# want to bump the superproject's gitlink to the latest upstream commit;
# there's no reason to create merge commits inside the vendored repos, and
# `--merge` breaks whenever the current pin has diverged from that branch.
- name: Update submodules to latest tracked branch
run: |
git submodule sync --recursive
git submodule update --remote --recursive
- name: Check for changes
id: check
run: |
if git diff --quiet; then
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "--- submodule pointer changes ---"
git submodule status --recursive || true
git diff --submodule=log -- vendor/ || true
fi
- name: Create PR with updates
if: steps.check.outputs.changed == 'true'
run: |
BRANCH="chore/update-submodules-$(date +%Y%m%d-%H%M%S)"
git checkout -b "$BRANCH"
git add vendor/
git commit -m "chore: update vendor submodules to latest upstream"
git push origin "$BRANCH"
gh pr create \
--title "chore: update vendor submodules" \
--body "Automated submodule update to the latest upstream commit on each submodule's tracked branch (see \`.gitmodules\`). Review the pointer diff before merging." \
--base main \
--head "$BRANCH"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-124
View File
@@ -1,124 +0,0 @@
name: Verify Pipeline Determinism
on:
push:
branches: [ main, master, 'claude/**' ]
paths:
- 'archive/v1/src/core/**'
- 'archive/v1/src/hardware/**'
- 'archive/v1/data/proof/**'
- 'archive/v1/requirements-lock.txt'
- '.github/workflows/verify-pipeline.yml'
pull_request:
branches: [ main, master ]
paths:
- 'archive/v1/src/core/**'
- 'archive/v1/src/hardware/**'
- 'archive/v1/data/proof/**'
- 'archive/v1/requirements-lock.txt'
- '.github/workflows/verify-pipeline.yml'
workflow_dispatch:
jobs:
verify-determinism:
name: Verify Pipeline Determinism
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.11']
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install pinned dependencies
run: |
python -m pip install --upgrade pip
pip install -r archive/v1/requirements-lock.txt
- name: Verify reference signal is reproducible
run: |
echo "=== Regenerating reference signal ==="
python archive/v1/data/proof/generate_reference_signal.py
echo ""
echo "=== Checking data file matches committed version ==="
# The regenerated file should be identical to the committed one
# (We compare the metadata file since data file is large)
python -c "
import json, hashlib
with open('archive/v1/data/proof/sample_csi_meta.json') as f:
meta = json.load(f)
assert meta['is_synthetic'] == True, 'Metadata must mark signal as synthetic'
assert meta['numpy_seed'] == 42, 'Seed must be 42'
print('Reference signal metadata validated.')
"
- name: Run pipeline verification
working-directory: archive/v1
env:
# Pin thread count for scipy.fft / BLAS — multi-threaded reduction
# order is otherwise non-deterministic across CI runs (issue #560
# follow-up: 9- and 6-decimal quantization were not enough because
# the divergence is from threading order, not SIMD reordering).
# Single-threaded keeps the proof reproducible at a ~2-3x slowdown.
OMP_NUM_THREADS: "1"
OPENBLAS_NUM_THREADS: "1"
MKL_NUM_THREADS: "1"
VECLIB_MAXIMUM_THREADS: "1"
NUMEXPR_NUM_THREADS: "1"
run: |
echo "=== Running pipeline verification ==="
python data/proof/verify.py
echo ""
echo "Pipeline verification PASSED."
- name: Run verification twice to confirm determinism
working-directory: archive/v1
env:
OMP_NUM_THREADS: "1"
OPENBLAS_NUM_THREADS: "1"
MKL_NUM_THREADS: "1"
VECLIB_MAXIMUM_THREADS: "1"
NUMEXPR_NUM_THREADS: "1"
run: |
echo "=== Second run for determinism confirmation ==="
python data/proof/verify.py
echo "Determinism confirmed across multiple runs."
- name: Check for unseeded np.random in production code
run: |
echo "=== Scanning for unseeded np.random usage in production code ==="
# Search for np.random calls without a seed in production code
# Exclude test files, proof data generators, and known parser placeholders
VIOLATIONS=$(grep -rn "np\.random\." archive/v1/src/ \
--include="*.py" \
--exclude-dir="__pycache__" \
| grep -v "np\.random\.RandomState" \
| grep -v "np\.random\.seed" \
| grep -v "np\.random\.default_rng" \
| grep -v "# placeholder" \
| grep -v "# mock" \
| grep -v "# test" \
|| true)
if [ -n "$VIOLATIONS" ]; then
echo ""
echo "WARNING: Found potential unseeded np.random usage in production code:"
echo "$VIOLATIONS"
echo ""
echo "Each np.random call should either:"
echo " 1. Use np.random.RandomState(seed) or np.random.default_rng(seed)"
echo " 2. Be in a test/mock context (add '# placeholder' comment)"
echo ""
# Note: This is a warning, not a failure, because some existing
# placeholder code in parsers uses np.random for mock data.
# Once hardware integration is complete, these should be removed.
echo "WARNING: Review the above usages. Existing parser placeholders are expected."
else
echo "No unseeded np.random usage found in production code."
fi
+1 -76
View File
@@ -1,45 +1,3 @@
# Local Claude config (contains WiFi credentials and machine-specific paths)
CLAUDE.local.md
# ESP32 firmware build artifacts and local config (contains WiFi credentials)
firmware/esp32-csi-node/build/
firmware/esp32-csi-node/sdkconfig
firmware/esp32-csi-node/sdkconfig.defaults
firmware/esp32-csi-node/sdkconfig.old
# Downloaded WASM3 source (fetched at configure time)
firmware/esp32-csi-node/components/wasm3/wasm3-src/
# ESP-IDF managed components (downloaded at build time)
firmware/esp32-csi-node/managed_components/
firmware/esp32-csi-node/dependencies.lock
firmware/esp32-csi-node/sdkconfig.defaults.bak
# ESP-IDF set-target backup (local only)
firmware/esp32-hello-world/sdkconfig.old
# Claude Flow swarm runtime state
.swarm/
# CSI recordings (local training data, machine-specific)
rust-port/wifi-densepose-rs/data/recordings/
# NVS partition images and CSVs (contain WiFi credentials)
nvs.bin
nvs_config.csv
nvs_provision.bin
firmware/esp32-csi-node/nvs_seed.csv
firmware/esp32-csi-node/nvs_seed.bin
firmware/esp32-csi-node/nvs_config.bin
firmware/esp32-csi-node/nvs_wifi.bin
firmware/esp32-csi-node/nvs.bin
# Catch any other NVS binaries/CSVs with credentials
**/nvs_*.bin
**/nvs_*.csv
# Working artifacts that should not land in root
/*.wasm
/esp32_*.txt
/serial_error.txt
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
@@ -229,42 +187,9 @@ cython_debug/
# PyPI configuration file
.pypirc
# Compiled Swift helper binaries (macOS WiFi sensing)
v1/src/sensing/mac_wifi
# Cursor
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
# refer to https://docs.cursor.com/context/ignore-files
.cursorignore
.cursorindexingignore
# Claude Flow runtime artifacts (auto-generated, machine-specific)
**/daemon.pid
**/pending-insights.jsonl
**/vectors.db
**/memory.db
**/.claude-flow/sessions/session-*.json
**/.claude-flow/sessions/current.json
# Node modules (should use npm ci, not committed)
**/node_modules/
# Local build scripts
firmware/esp32-csi-node/build_firmware.batdata/
models/
demo_pointcloud.ply
demo_splats.json
# rvCSI napi-rs addon — generated by `napi build` (do not commit)
v2/crates/rvcsi-node/*.node
v2/crates/rvcsi-node/binding.js
v2/crates/rvcsi-node/binding.d.ts
v2/crates/rvcsi-node/npm/
# AetherArena private optimization staging — never published until reviewed
aether-arena/staging/
# MM-Fi benchmark dataset archives — large data, fetch separately, never commit
assets/MM-Fi/E0*.zip
assets/MM-Fi/*.zip
.cursorindexingignore
+347
View File
@@ -0,0 +1,347 @@
# GitLab CI/CD Pipeline for WiFi-DensePose
# This pipeline provides an alternative to GitHub Actions for GitLab users
stages:
- validate
- test
- security
- build
- deploy-staging
- deploy-production
- monitor
variables:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: "/certs"
REGISTRY: $CI_REGISTRY
IMAGE_NAME: $CI_REGISTRY_IMAGE
PYTHON_VERSION: "3.11"
KUBECONFIG: /tmp/kubeconfig
# Global before_script
before_script:
- echo "Pipeline started for $CI_COMMIT_REF_NAME"
- export IMAGE_TAG=${CI_COMMIT_SHA:0:8}
# Code Quality and Validation
code-quality:
stage: validate
image: python:$PYTHON_VERSION
before_script:
- pip install --upgrade pip
- pip install -r requirements.txt
- pip install black flake8 mypy bandit safety
script:
- echo "Running code quality checks..."
- black --check --diff src/ tests/
- flake8 src/ tests/ --max-line-length=88 --extend-ignore=E203,W503
- mypy src/ --ignore-missing-imports
- bandit -r src/ -f json -o bandit-report.json || true
- safety check --json --output safety-report.json || true
artifacts:
reports:
junit: bandit-report.json
paths:
- bandit-report.json
- safety-report.json
expire_in: 1 week
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
# Unit Tests
unit-tests:
stage: test
image: python:$PYTHON_VERSION
services:
- postgres:15
- redis:7
variables:
POSTGRES_DB: test_wifi_densepose
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/test_wifi_densepose
REDIS_URL: redis://redis:6379/0
ENVIRONMENT: test
before_script:
- pip install --upgrade pip
- pip install -r requirements.txt
- pip install pytest-cov pytest-xdist
script:
- echo "Running unit tests..."
- pytest tests/unit/ -v --cov=src --cov-report=xml --cov-report=html --junitxml=junit.xml
coverage: '/TOTAL.*\s+(\d+%)$/'
artifacts:
reports:
junit: junit.xml
coverage_report:
coverage_format: cobertura
path: coverage.xml
paths:
- htmlcov/
expire_in: 1 week
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
# Integration Tests
integration-tests:
stage: test
image: python:$PYTHON_VERSION
services:
- postgres:15
- redis:7
variables:
POSTGRES_DB: test_wifi_densepose
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/test_wifi_densepose
REDIS_URL: redis://redis:6379/0
ENVIRONMENT: test
before_script:
- pip install --upgrade pip
- pip install -r requirements.txt
- pip install pytest
script:
- echo "Running integration tests..."
- pytest tests/integration/ -v --junitxml=integration-junit.xml
artifacts:
reports:
junit: integration-junit.xml
expire_in: 1 week
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
# Security Scanning
security-scan:
stage: security
image: python:$PYTHON_VERSION
before_script:
- pip install --upgrade pip
- pip install -r requirements.txt
- pip install bandit semgrep safety
script:
- echo "Running security scans..."
- bandit -r src/ -f sarif -o bandit-results.sarif || true
- semgrep --config=p/security-audit --config=p/secrets --config=p/python --sarif --output=semgrep.sarif src/ || true
- safety check --json --output safety-report.json || true
artifacts:
reports:
sast:
- bandit-results.sarif
- semgrep.sarif
paths:
- safety-report.json
expire_in: 1 week
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
# Container Security Scan
container-security:
stage: security
image: docker:latest
services:
- docker:dind
before_script:
- docker info
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
script:
- echo "Building and scanning container..."
- docker build -t $IMAGE_NAME:$IMAGE_TAG .
- docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v $PWD:/tmp/.cache/ aquasec/trivy:latest image --format sarif --output /tmp/.cache/trivy-results.sarif $IMAGE_NAME:$IMAGE_TAG || true
artifacts:
reports:
container_scanning: trivy-results.sarif
expire_in: 1 week
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
# Build and Push Docker Image
build-image:
stage: build
image: docker:latest
services:
- docker:dind
before_script:
- docker info
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
script:
- echo "Building Docker image..."
- docker build --target production -t $IMAGE_NAME:$IMAGE_TAG -t $IMAGE_NAME:latest .
- docker push $IMAGE_NAME:$IMAGE_TAG
- docker push $IMAGE_NAME:latest
- echo "Image pushed: $IMAGE_NAME:$IMAGE_TAG"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_TAG
# Deploy to Staging
deploy-staging:
stage: deploy-staging
image: bitnami/kubectl:latest
environment:
name: staging
url: https://staging.wifi-densepose.com
before_script:
- echo "$KUBE_CONFIG_STAGING" | base64 -d > $KUBECONFIG
- kubectl config view
script:
- echo "Deploying to staging environment..."
- kubectl set image deployment/wifi-densepose wifi-densepose=$IMAGE_NAME:$IMAGE_TAG -n wifi-densepose-staging
- kubectl rollout status deployment/wifi-densepose -n wifi-densepose-staging --timeout=600s
- kubectl get pods -n wifi-densepose-staging -l app=wifi-densepose
- echo "Staging deployment completed"
after_script:
- sleep 30
- curl -f https://staging.wifi-densepose.com/health || exit 1
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual
allow_failure: false
# Deploy to Production
deploy-production:
stage: deploy-production
image: bitnami/kubectl:latest
environment:
name: production
url: https://wifi-densepose.com
before_script:
- echo "$KUBE_CONFIG_PRODUCTION" | base64 -d > $KUBECONFIG
- kubectl config view
script:
- echo "Deploying to production environment..."
# Backup current deployment
- kubectl get deployment wifi-densepose -n wifi-densepose -o yaml > backup-deployment.yaml
# Blue-Green Deployment
- kubectl patch deployment wifi-densepose -n wifi-densepose -p '{"spec":{"template":{"metadata":{"labels":{"version":"green"}}}}}'
- kubectl set image deployment/wifi-densepose wifi-densepose=$IMAGE_NAME:$IMAGE_TAG -n wifi-densepose
- kubectl rollout status deployment/wifi-densepose -n wifi-densepose --timeout=600s
- kubectl wait --for=condition=ready pod -l app=wifi-densepose,version=green -n wifi-densepose --timeout=300s
# Switch traffic
- kubectl patch service wifi-densepose-service -n wifi-densepose -p '{"spec":{"selector":{"version":"green"}}}'
- echo "Production deployment completed"
after_script:
- sleep 30
- curl -f https://wifi-densepose.com/health || exit 1
artifacts:
paths:
- backup-deployment.yaml
expire_in: 1 week
rules:
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual
allow_failure: false
# Post-deployment Monitoring
monitor-deployment:
stage: monitor
image: curlimages/curl:latest
script:
- echo "Monitoring deployment health..."
- |
if [ "$CI_ENVIRONMENT_NAME" = "production" ]; then
BASE_URL="https://wifi-densepose.com"
else
BASE_URL="https://staging.wifi-densepose.com"
fi
- |
for i in $(seq 1 10); do
echo "Health check $i/10"
curl -f $BASE_URL/health || exit 1
curl -f $BASE_URL/api/v1/status || exit 1
sleep 30
done
- echo "Monitoring completed successfully"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: on_success
- if: $CI_COMMIT_TAG
when: on_success
allow_failure: true
# Rollback Job (Manual)
rollback:
stage: deploy-production
image: bitnami/kubectl:latest
environment:
name: production
url: https://wifi-densepose.com
before_script:
- echo "$KUBE_CONFIG_PRODUCTION" | base64 -d > $KUBECONFIG
script:
- echo "Rolling back deployment..."
- kubectl rollout undo deployment/wifi-densepose -n wifi-densepose
- kubectl rollout status deployment/wifi-densepose -n wifi-densepose --timeout=600s
- kubectl get pods -n wifi-densepose -l app=wifi-densepose
- echo "Rollback completed"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual
allow_failure: false
# Cleanup old images
cleanup:
stage: monitor
image: docker:latest
services:
- docker:dind
before_script:
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
script:
- echo "Cleaning up old images..."
- |
# Keep only the last 10 images
IMAGES_TO_DELETE=$(docker images $IMAGE_NAME --format "table {{.Tag}}" | tail -n +2 | tail -n +11)
for tag in $IMAGES_TO_DELETE; do
if [ "$tag" != "latest" ] && [ "$tag" != "$IMAGE_TAG" ]; then
echo "Deleting image: $IMAGE_NAME:$tag"
docker rmi $IMAGE_NAME:$tag || true
fi
done
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: on_success
allow_failure: true
# Notification
notify-success:
stage: monitor
image: curlimages/curl:latest
script:
- |
if [ -n "$SLACK_WEBHOOK_URL" ]; then
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"✅ Pipeline succeeded for $CI_PROJECT_NAME on $CI_COMMIT_REF_NAME\"}" \
$SLACK_WEBHOOK_URL
fi
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: on_success
allow_failure: true
notify-failure:
stage: monitor
image: curlimages/curl:latest
script:
- |
if [ -n "$SLACK_WEBHOOK_URL" ]; then
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"❌ Pipeline failed for $CI_PROJECT_NAME on $CI_COMMIT_REF_NAME\"}" \
$SLACK_WEBHOOK_URL
fi
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: on_failure
allow_failure: true
# Include additional pipeline configurations
include:
- template: Security/SAST.gitlab-ci.yml
- template: Security/Container-Scanning.gitlab-ci.yml
- template: Security/Dependency-Scanning.gitlab-ci.yml
- template: Security/License-Scanning.gitlab-ci.yml
-16
View File
@@ -1,16 +0,0 @@
[submodule "vendor/midstream"]
path = vendor/midstream
url = https://github.com/ruvnet/midstream
branch = main
[submodule "vendor/ruvector"]
path = vendor/ruvector
url = https://github.com/ruvnet/ruvector
branch = main
[submodule "vendor/sublinear-time-solver"]
path = vendor/sublinear-time-solver
url = https://github.com/ruvnet/sublinear-time-solver
branch = main
[submodule "vendor/rvcsi"]
path = vendor/rvcsi
url = https://github.com/ruvnet/rvcsi
branch = main
-2
View File
@@ -3,13 +3,11 @@
"claude-flow": {
"command": "npx",
"args": [
"-y",
"@claude-flow/cli@latest",
"mcp",
"start"
],
"env": {
"npm_config_update_notifier": "false",
"CLAUDE_FLOW_MODE": "v3",
"CLAUDE_FLOW_HOOKS_ENABLED": "true",
"CLAUDE_FLOW_TOPOLOGY": "hierarchical-mesh",
+402
View File
@@ -0,0 +1,402 @@
# Roo Modes and MCP Integration Guide
## Overview
This guide provides information about the various modes available in Roo and detailed documentation on the Model Context Protocol (MCP) integration capabilities.
Create by @ruvnet
## Available Modes
Roo offers specialized modes for different aspects of the development process:
### 📋 Specification Writer
- **Role**: Captures project context, functional requirements, edge cases, and constraints
- **Focus**: Translates requirements into modular pseudocode with TDD anchors
- **Best For**: Initial project planning and requirement gathering
### 🏗️ Architect
- **Role**: Designs scalable, secure, and modular architectures
- **Focus**: Creates architecture diagrams, data flows, and integration points
- **Best For**: System design and component relationships
### 🧠 Auto-Coder
- **Role**: Writes clean, efficient, modular code based on pseudocode and architecture
- **Focus**: Implements features with proper configuration and environment abstraction
- **Best For**: Feature implementation and code generation
### 🧪 Tester (TDD)
- **Role**: Implements Test-Driven Development (TDD, London School)
- **Focus**: Writes failing tests first, implements minimal code to pass, then refactors
- **Best For**: Ensuring code quality and test coverage
### 🪲 Debugger
- **Role**: Troubleshoots runtime bugs, logic errors, or integration failures
- **Focus**: Uses logs, traces, and stack analysis to isolate and fix bugs
- **Best For**: Resolving issues in existing code
### 🛡️ Security Reviewer
- **Role**: Performs static and dynamic audits to ensure secure code practices
- **Focus**: Flags secrets, poor modular boundaries, and oversized files
- **Best For**: Security audits and vulnerability assessments
### 📚 Documentation Writer
- **Role**: Writes concise, clear, and modular Markdown documentation
- **Focus**: Creates documentation that explains usage, integration, setup, and configuration
- **Best For**: Creating user guides and technical documentation
### 🔗 System Integrator
- **Role**: Merges outputs of all modes into a working, tested, production-ready system
- **Focus**: Verifies interface compatibility, shared modules, and configuration standards
- **Best For**: Combining components into a cohesive system
### 📈 Deployment Monitor
- **Role**: Observes the system post-launch, collecting performance data and user feedback
- **Focus**: Configures metrics, logs, uptime checks, and alerts
- **Best For**: Post-deployment observation and issue detection
### 🧹 Optimizer
- **Role**: Refactors, modularizes, and improves system performance
- **Focus**: Audits files for clarity, modularity, and size
- **Best For**: Code refinement and performance optimization
### 🚀 DevOps
- **Role**: Handles deployment, automation, and infrastructure operations
- **Focus**: Provisions infrastructure, configures environments, and sets up CI/CD pipelines
- **Best For**: Deployment and infrastructure management
### 🔐 Supabase Admin
- **Role**: Designs and implements database schemas, RLS policies, triggers, and functions
- **Focus**: Ensures secure, efficient, and scalable data management with Supabase
- **Best For**: Database management and Supabase integration
### ♾️ MCP Integration
- **Role**: Connects to and manages external services through MCP interfaces
- **Focus**: Ensures secure, efficient, and reliable communication with external APIs
- **Best For**: Integrating with third-party services
### ⚡️ SPARC Orchestrator
- **Role**: Orchestrates complex workflows by breaking down objectives into subtasks
- **Focus**: Ensures secure, modular, testable, and maintainable delivery
- **Best For**: Managing complex projects with multiple components
### ❓ Ask
- **Role**: Helps users navigate, ask, and delegate tasks to the correct modes
- **Focus**: Guides users to formulate questions using the SPARC methodology
- **Best For**: Getting started and understanding how to use Roo effectively
## MCP Integration Mode
The MCP Integration Mode (♾️) in Roo is designed specifically for connecting to and managing external services through MCP interfaces. This mode ensures secure, efficient, and reliable communication between your application and external service APIs.
### Key Features
- Establish connections to MCP servers and verify availability
- Configure and validate authentication for service access
- Implement data transformation and exchange between systems
- Robust error handling and retry mechanisms
- Documentation of integration points, dependencies, and usage patterns
### MCP Integration Workflow
| Phase | Action | Tool Preference |
|-------|--------|-----------------|
| 1. Connection | Establish connection to MCP servers and verify availability | `use_mcp_tool` for server operations |
| 2. Authentication | Configure and validate authentication for service access | `use_mcp_tool` with proper credentials |
| 3. Data Exchange | Implement data transformation and exchange between systems | `use_mcp_tool` for operations, `apply_diff` for code |
| 4. Error Handling | Implement robust error handling and retry mechanisms | `apply_diff` for code modifications |
| 5. Documentation | Document integration points, dependencies, and usage patterns | `insert_content` for documentation |
### Non-Negotiable Requirements
- ✅ ALWAYS verify MCP server availability before operations
- ✅ NEVER store credentials or tokens in code
- ✅ ALWAYS implement proper error handling for all API calls
- ✅ ALWAYS validate inputs and outputs for all operations
- ✅ NEVER use hardcoded environment variables
- ✅ ALWAYS document all integration points and dependencies
- ✅ ALWAYS use proper parameter validation before tool execution
- ✅ ALWAYS include complete parameters for MCP tool operations
# Agentic Coding MCPs
## Overview
This guide provides detailed information on Management Control Panel (MCP) integration capabilities. MCP enables seamless agent workflows by connecting to more than 80 servers, covering development, AI, data management, productivity, cloud storage, e-commerce, finance, communication, and design. Each server offers specialized tools, allowing agents to securely access, automate, and manage external services through a unified and modular system. This approach supports building dynamic, scalable, and intelligent workflows with minimal setup and maximum flexibility.
## Install via NPM
```
npx create-sparc init --force
```
---
## Available MCP Servers
### 🛠️ Development & Coding
| | Service | Description |
|:------|:--------------|:-----------------------------------|
| 🐙 | GitHub | Repository management, issues, PRs |
| 🦊 | GitLab | Repo management, CI/CD pipelines |
| 🧺 | Bitbucket | Code collaboration, repo hosting |
| 🐳 | DockerHub | Container registry and management |
| 📦 | npm | Node.js package registry |
| 🐍 | PyPI | Python package index |
| 🤗 | HuggingFace Hub| AI model repository |
| 🧠 | Cursor | AI-powered code editor |
| 🌊 | Windsurf | AI development platform |
---
### 🤖 AI & Machine Learning
| | Service | Description |
|:------|:--------------|:-----------------------------------|
| 🔥 | OpenAI | GPT models, DALL-E, embeddings |
| 🧩 | Perplexity AI | AI search and question answering |
| 🧠 | Cohere | NLP models |
| 🧬 | Replicate | AI model hosting |
| 🎨 | Stability AI | Image generation AI |
| 🚀 | Groq | High-performance AI inference |
| 📚 | LlamaIndex | Data framework for LLMs |
| 🔗 | LangChain | Framework for LLM apps |
| ⚡ | Vercel AI | AI SDK, fast deployment |
| 🛠️ | AutoGen | Multi-agent orchestration |
| 🧑‍🤝‍🧑 | CrewAI | Agent team framework |
| 🧠 | Huggingface | Model hosting and APIs |
---
### 📈 Data & Analytics
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| 🛢️ | Supabase | Database, Auth, Storage backend |
| 🔍 | Ahrefs | SEO analytics |
| 🧮 | Code Interpreter| Code execution and data analysis |
---
### 📅 Productivity & Collaboration
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| ✉️ | Gmail | Email service |
| 📹 | YouTube | Video sharing platform |
| 👔 | LinkedIn | Professional network |
| 📰 | HackerNews | Tech news discussions |
| 🗒️ | Notion | Knowledge management |
| 💬 | Slack | Team communication |
| ✅ | Asana | Project management |
| 📋 | Trello | Kanban boards |
| 🛠️ | Jira | Issue tracking and projects |
| 🎟️ | Zendesk | Customer service |
| 🎮 | Discord | Community messaging |
| 📲 | Telegram | Messaging app |
---
### 🗂️ File Storage & Management
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| ☁️ | Google Drive | Cloud file storage |
| 📦 | Dropbox | Cloud file sharing |
| 📁 | Box | Enterprise file storage |
| 🪟 | OneDrive | Microsoft cloud storage |
| 🧠 | Mem0 | Knowledge storage, notes |
---
### 🔎 Search & Web Information
| | Service | Description |
|:------|:----------------|:---------------------------------|
| 🌐 | Composio Search | Unified web search for agents |
---
### 🛒 E-commerce & Finance
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| 🛍️ | Shopify | E-commerce platform |
| 💳 | Stripe | Payment processing |
| 💰 | PayPal | Online payments |
| 📒 | QuickBooks | Accounting software |
| 📈 | Xero | Accounting and finance |
| 🏦 | Plaid | Financial data APIs |
---
### 📣 Marketing & Communications
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| 🐒 | MailChimp | Email marketing platform |
| ✉️ | SendGrid | Email delivery service |
| 📞 | Twilio | SMS and calling APIs |
| 💬 | Intercom | Customer messaging |
| 🎟️ | Freshdesk | Customer support |
---
### 🛜 Social Media & Publishing
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| 👥 | Facebook | Social networking |
| 📷 | Instagram | Photo sharing |
| 🐦 | Twitter | Microblogging platform |
| 👽 | Reddit | Social news aggregation |
| ✍️ | Medium | Blogging platform |
| 🌐 | WordPress | Website and blog publishing |
| 🌎 | Webflow | Web design and hosting |
---
### 🎨 Design & Digital Assets
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| 🎨 | Figma | Collaborative UI design |
| 🎞️ | Adobe | Creative tools and software |
---
### 🗓️ Scheduling & Events
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| 📆 | Calendly | Appointment scheduling |
| 🎟️ | Eventbrite | Event management and tickets |
| 📅 | Calendar Google | Google Calendar Integration |
| 📅 | Calendar Outlook| Outlook Calendar Integration |
---
## 🧩 Using MCP Tools
To use an MCP server:
1. Connect to the desired MCP endpoint or install server (e.g., Supabase via `npx`).
2. Authenticate with your credentials.
3. Trigger available actions through Roo workflows.
4. Maintain security and restrict only necessary permissions.
### Example: GitHub Integration
```
<!-- Initiate connection -->
<use_mcp_tool>
<server_name>github</server_name>
<tool_name>GITHUB_INITIATE_CONNECTION</tool_name>
<arguments>{}</arguments>
</use_mcp_tool>
<!-- List pull requests -->
<use_mcp_tool>
<server_name>github</server_name>
<tool_name>GITHUB_PULLS_LIST</tool_name>
<arguments>{"owner": "username", "repo": "repository-name"}</arguments>
</use_mcp_tool>
```
### Example: OpenAI Integration
```
<!-- Initiate connection -->
<use_mcp_tool>
<server_name>openai</server_name>
<tool_name>OPENAI_INITIATE_CONNECTION</tool_name>
<arguments>{}</arguments>
</use_mcp_tool>
<!-- Generate text with GPT -->
<use_mcp_tool>
<server_name>openai</server_name>
<tool_name>OPENAI_CHAT_COMPLETION</tool_name>
<arguments>{
"model": "gpt-4",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Explain quantum computing in simple terms."}
],
"temperature": 0.7
}</arguments>
</use_mcp_tool>
```
## Tool Usage Guidelines
### Primary Tools
- `use_mcp_tool`: Use for all MCP server operations
```
<use_mcp_tool>
<server_name>server_name</server_name>
<tool_name>tool_name</tool_name>
<arguments>{ "param1": "value1", "param2": "value2" }</arguments>
</use_mcp_tool>
```
- `access_mcp_resource`: Use for accessing MCP resources
```
<access_mcp_resource>
<server_name>server_name</server_name>
<uri>resource://path/to/resource</uri>
</access_mcp_resource>
```
- `apply_diff`: Use for code modifications with complete search and replace blocks
```
<apply_diff>
<path>file/path.js</path>
<diff>
<<<<<<< SEARCH
// Original code
=======
// Updated code
>>>>>>> REPLACE
</diff>
</apply_diff>
```
### Secondary Tools
- `insert_content`: Use for documentation and adding new content
- `execute_command`: Use for testing API connections and validating integrations
- `search_and_replace`: Use only when necessary and always include both parameters
## Detailed Documentation
For detailed information about each MCP server and its available tools, refer to the individual documentation files in the `.roo/rules-mcp/` directory:
- [GitHub](./rules-mcp/github.md)
- [Supabase](./rules-mcp/supabase.md)
- [Ahrefs](./rules-mcp/ahrefs.md)
- [Gmail](./rules-mcp/gmail.md)
- [YouTube](./rules-mcp/youtube.md)
- [LinkedIn](./rules-mcp/linkedin.md)
- [OpenAI](./rules-mcp/openai.md)
- [Notion](./rules-mcp/notion.md)
- [Slack](./rules-mcp/slack.md)
- [Google Drive](./rules-mcp/google_drive.md)
- [HackerNews](./rules-mcp/hackernews.md)
- [Composio Search](./rules-mcp/composio_search.md)
- [Mem0](./rules-mcp/mem0.md)
- [PerplexityAI](./rules-mcp/perplexityai.md)
- [CodeInterpreter](./rules-mcp/codeinterpreter.md)
## Best Practices
1. Always initiate a connection before attempting to use any MCP tools
2. Implement retry mechanisms with exponential backoff for transient failures
3. Use circuit breakers to prevent cascading failures
4. Implement request batching to optimize API usage
5. Use proper logging for all API operations
6. Implement data validation for all incoming and outgoing data
7. Use proper error codes and messages for API responses
8. Implement proper timeout handling for all API calls
9. Use proper versioning for API integrations
10. Implement proper rate limiting to prevent API abuse
11. Use proper caching strategies to reduce API calls
+257
View File
@@ -0,0 +1,257 @@
{
"mcpServers": {
"supabase": {
"command": "npx",
"args": [
"-y",
"@supabase/mcp-server-supabase@latest",
"--access-token",
"${env:SUPABASE_ACCESS_TOKEN}"
],
"alwaysAllow": [
"list_tables",
"execute_sql",
"listTables",
"list_projects",
"list_organizations",
"get_organization",
"apply_migration",
"get_project",
"execute_query",
"generate_typescript_types",
"listProjects"
]
},
"composio_search": {
"url": "https://mcp.composio.dev/composio_search/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"mem0": {
"url": "https://mcp.composio.dev/mem0/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"perplexityai": {
"url": "https://mcp.composio.dev/perplexityai/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"codeinterpreter": {
"url": "https://mcp.composio.dev/codeinterpreter/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"gmail": {
"url": "https://mcp.composio.dev/gmail/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"youtube": {
"url": "https://mcp.composio.dev/youtube/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"ahrefs": {
"url": "https://mcp.composio.dev/ahrefs/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"linkedin": {
"url": "https://mcp.composio.dev/linkedin/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"hackernews": {
"url": "https://mcp.composio.dev/hackernews/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"notion": {
"url": "https://mcp.composio.dev/notion/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"slack": {
"url": "https://mcp.composio.dev/slack/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"asana": {
"url": "https://mcp.composio.dev/asana/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"trello": {
"url": "https://mcp.composio.dev/trello/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"jira": {
"url": "https://mcp.composio.dev/jira/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"zendesk": {
"url": "https://mcp.composio.dev/zendesk/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"dropbox": {
"url": "https://mcp.composio.dev/dropbox/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"box": {
"url": "https://mcp.composio.dev/box/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"onedrive": {
"url": "https://mcp.composio.dev/onedrive/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"google_drive": {
"url": "https://mcp.composio.dev/google_drive/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"calendar": {
"url": "https://mcp.composio.dev/calendar/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"outlook": {
"url": "https://mcp.composio.dev/outlook/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"salesforce": {
"url": "https://mcp.composio.dev/salesforce/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"hubspot": {
"url": "https://mcp.composio.dev/hubspot/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"airtable": {
"url": "https://mcp.composio.dev/airtable/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"clickup": {
"url": "https://mcp.composio.dev/clickup/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"monday": {
"url": "https://mcp.composio.dev/monday/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"linear": {
"url": "https://mcp.composio.dev/linear/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"intercom": {
"url": "https://mcp.composio.dev/intercom/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"freshdesk": {
"url": "https://mcp.composio.dev/freshdesk/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"shopify": {
"url": "https://mcp.composio.dev/shopify/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"stripe": {
"url": "https://mcp.composio.dev/stripe/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"paypal": {
"url": "https://mcp.composio.dev/paypal/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"quickbooks": {
"url": "https://mcp.composio.dev/quickbooks/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"xero": {
"url": "https://mcp.composio.dev/xero/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"mailchimp": {
"url": "https://mcp.composio.dev/mailchimp/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"sendgrid": {
"url": "https://mcp.composio.dev/sendgrid/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"twilio": {
"url": "https://mcp.composio.dev/twilio/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"plaid": {
"url": "https://mcp.composio.dev/plaid/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"zoom": {
"url": "https://mcp.composio.dev/zoom/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"calendar_google": {
"url": "https://mcp.composio.dev/calendar_google/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"calendar_outlook": {
"url": "https://mcp.composio.dev/calendar_outlook/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"discord": {
"url": "https://mcp.composio.dev/discord/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"telegram": {
"url": "https://mcp.composio.dev/telegram/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"facebook": {
"url": "https://mcp.composio.dev/facebook/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"instagram": {
"url": "https://mcp.composio.dev/instagram/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"twitter": {
"url": "https://mcp.composio.dev/twitter/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"reddit": {
"url": "https://mcp.composio.dev/reddit/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"medium": {
"url": "https://mcp.composio.dev/medium/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"wordpress": {
"url": "https://mcp.composio.dev/wordpress/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"webflow": {
"url": "https://mcp.composio.dev/webflow/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"figma": {
"url": "https://mcp.composio.dev/figma/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"adobe": {
"url": "https://mcp.composio.dev/adobe/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"calendly": {
"url": "https://mcp.composio.dev/calendly/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"eventbrite": {
"url": "https://mcp.composio.dev/eventbrite/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"huggingface": {
"url": "https://mcp.composio.dev/huggingface/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"openai": {
"url": "https://mcp.composio.dev/openai/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"replicate": {
"url": "https://mcp.composio.dev/replicate/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"cohere": {
"url": "https://mcp.composio.dev/cohere/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"stabilityai": {
"url": "https://mcp.composio.dev/stabilityai/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"groq": {
"url": "https://mcp.composio.dev/groq/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"llamaindex": {
"url": "https://mcp.composio.dev/llamaindex/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"langchain": {
"url": "https://mcp.composio.dev/langchain/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"vercelai": {
"url": "https://mcp.composio.dev/vercelai/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"autogen": {
"url": "https://mcp.composio.dev/autogen/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"crewai": {
"url": "https://mcp.composio.dev/crewai/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"cursor": {
"url": "https://mcp.composio.dev/cursor/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"windsurf": {
"url": "https://mcp.composio.dev/windsurf/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"python": {
"url": "https://mcp.composio.dev/python/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"nodejs": {
"url": "https://mcp.composio.dev/nodejs/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"typescript": {
"url": "https://mcp.composio.dev/typescript/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"github": {
"url": "https://mcp.composio.dev/github/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"gitlab": {
"url": "https://mcp.composio.dev/gitlab/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"bitbucket": {
"url": "https://mcp.composio.dev/bitbucket/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"dockerhub": {
"url": "https://mcp.composio.dev/dockerhub/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"npm": {
"url": "https://mcp.composio.dev/npm/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"pypi": {
"url": "https://mcp.composio.dev/pypi/abandoned-creamy-horse-Y39-hm?agent=cursor"
},
"huggingfacehub": {
"url": "https://mcp.composio.dev/huggingfacehub/abandoned-creamy-horse-Y39-hm?agent=cursor"
}
}
}
+165
View File
@@ -0,0 +1,165 @@
# Agentic Coding MCPs
## Overview
This guide provides detailed information on Management Control Panel (MCP) integration capabilities. MCP enables seamless agent workflows by connecting to more than 80 servers, covering development, AI, data management, productivity, cloud storage, e-commerce, finance, communication, and design. Each server offers specialized tools, allowing agents to securely access, automate, and manage external services through a unified and modular system. This approach supports building dynamic, scalable, and intelligent workflows with minimal setup and maximum flexibility.
## Install via NPM
```
npx create-sparc init --force
```
---
## Available MCP Servers
### 🛠️ Development & Coding
| | Service | Description |
|:------|:--------------|:-----------------------------------|
| 🐙 | GitHub | Repository management, issues, PRs |
| 🦊 | GitLab | Repo management, CI/CD pipelines |
| 🧺 | Bitbucket | Code collaboration, repo hosting |
| 🐳 | DockerHub | Container registry and management |
| 📦 | npm | Node.js package registry |
| 🐍 | PyPI | Python package index |
| 🤗 | HuggingFace Hub| AI model repository |
| 🧠 | Cursor | AI-powered code editor |
| 🌊 | Windsurf | AI development platform |
---
### 🤖 AI & Machine Learning
| | Service | Description |
|:------|:--------------|:-----------------------------------|
| 🔥 | OpenAI | GPT models, DALL-E, embeddings |
| 🧩 | Perplexity AI | AI search and question answering |
| 🧠 | Cohere | NLP models |
| 🧬 | Replicate | AI model hosting |
| 🎨 | Stability AI | Image generation AI |
| 🚀 | Groq | High-performance AI inference |
| 📚 | LlamaIndex | Data framework for LLMs |
| 🔗 | LangChain | Framework for LLM apps |
| ⚡ | Vercel AI | AI SDK, fast deployment |
| 🛠️ | AutoGen | Multi-agent orchestration |
| 🧑‍🤝‍🧑 | CrewAI | Agent team framework |
| 🧠 | Huggingface | Model hosting and APIs |
---
### 📈 Data & Analytics
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| 🛢️ | Supabase | Database, Auth, Storage backend |
| 🔍 | Ahrefs | SEO analytics |
| 🧮 | Code Interpreter| Code execution and data analysis |
---
### 📅 Productivity & Collaboration
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| ✉️ | Gmail | Email service |
| 📹 | YouTube | Video sharing platform |
| 👔 | LinkedIn | Professional network |
| 📰 | HackerNews | Tech news discussions |
| 🗒️ | Notion | Knowledge management |
| 💬 | Slack | Team communication |
| ✅ | Asana | Project management |
| 📋 | Trello | Kanban boards |
| 🛠️ | Jira | Issue tracking and projects |
| 🎟️ | Zendesk | Customer service |
| 🎮 | Discord | Community messaging |
| 📲 | Telegram | Messaging app |
---
### 🗂️ File Storage & Management
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| ☁️ | Google Drive | Cloud file storage |
| 📦 | Dropbox | Cloud file sharing |
| 📁 | Box | Enterprise file storage |
| 🪟 | OneDrive | Microsoft cloud storage |
| 🧠 | Mem0 | Knowledge storage, notes |
---
### 🔎 Search & Web Information
| | Service | Description |
|:------|:----------------|:---------------------------------|
| 🌐 | Composio Search | Unified web search for agents |
---
### 🛒 E-commerce & Finance
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| 🛍️ | Shopify | E-commerce platform |
| 💳 | Stripe | Payment processing |
| 💰 | PayPal | Online payments |
| 📒 | QuickBooks | Accounting software |
| 📈 | Xero | Accounting and finance |
| 🏦 | Plaid | Financial data APIs |
---
### 📣 Marketing & Communications
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| 🐒 | MailChimp | Email marketing platform |
| ✉️ | SendGrid | Email delivery service |
| 📞 | Twilio | SMS and calling APIs |
| 💬 | Intercom | Customer messaging |
| 🎟️ | Freshdesk | Customer support |
---
### 🛜 Social Media & Publishing
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| 👥 | Facebook | Social networking |
| 📷 | Instagram | Photo sharing |
| 🐦 | Twitter | Microblogging platform |
| 👽 | Reddit | Social news aggregation |
| ✍️ | Medium | Blogging platform |
| 🌐 | WordPress | Website and blog publishing |
| 🌎 | Webflow | Web design and hosting |
---
### 🎨 Design & Digital Assets
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| 🎨 | Figma | Collaborative UI design |
| 🎞️ | Adobe | Creative tools and software |
---
### 🗓️ Scheduling & Events
| | Service | Description |
|:------|:---------------|:-----------------------------------|
| 📆 | Calendly | Appointment scheduling |
| 🎟️ | Eventbrite | Event management and tickets |
| 📅 | Calendar Google | Google Calendar Integration |
| 📅 | Calendar Outlook| Outlook Calendar Integration |
---
## 🧩 Using MCP Tools
To use an MCP server:
1. Connect to the desired MCP endpoint or install server (e.g., Supabase via `npx`).
2. Authenticate with your credentials.
3. Trigger available actions through Roo workflows.
4. Maintain security and restrict only necessary permissions.
+176
View File
@@ -0,0 +1,176 @@
Goal: Design robust system architectures with clear boundaries and interfaces
0 · Onboarding
First time a user speaks, reply with one line and one emoji: "🏛️ Ready to architect your vision!"
1 · Unified Role Definition
You are Roo Architect, an autonomous architectural design partner in VS Code. Plan, visualize, and document system architectures while providing technical insights on component relationships, interfaces, and boundaries. Detect intent directly from conversation—no explicit mode switching.
2 · Architectural Workflow
Step | Action
1 Requirements Analysis | Clarify system goals, constraints, non-functional requirements, and stakeholder needs.
2 System Decomposition | Identify core components, services, and their responsibilities; establish clear boundaries.
3 Interface Design | Define clean APIs, data contracts, and communication patterns between components.
4 Visualization | Create clear system diagrams showing component relationships, data flows, and deployment models.
5 Validation | Verify the architecture against requirements, quality attributes, and potential failure modes.
3 · Must Block (non-negotiable)
• Every component must have clearly defined responsibilities
• All interfaces must be explicitly documented
• System boundaries must be established with proper access controls
• Data flows must be traceable through the system
• Security and privacy considerations must be addressed at the design level
• Performance and scalability requirements must be considered
• Each architectural decision must include rationale
4 · Architectural Patterns & Best Practices
• Apply appropriate patterns (microservices, layered, event-driven, etc.) based on requirements
• Design for resilience with proper error handling and fault tolerance
• Implement separation of concerns across all system boundaries
• Establish clear data ownership and consistency models
• Design for observability with logging, metrics, and tracing
• Consider deployment and operational concerns early
• Document trade-offs and alternatives considered for key decisions
• Maintain a glossary of domain terms and concepts
• Create views for different stakeholders (developers, operators, business)
5 · Diagramming Guidelines
• Use consistent notation (preferably C4, UML, or architecture decision records)
• Include legend explaining symbols and relationships
• Provide multiple levels of abstraction (context, container, component)
• Clearly label all components, connectors, and boundaries
• Show data flows with directionality
• Highlight critical paths and potential bottlenecks
• Document both runtime and deployment views
• Include sequence diagrams for key interactions
• Annotate with quality attributes and constraints
6 · Service Boundary Definition
• Each service should have a single, well-defined responsibility
• Services should own their data and expose it through well-defined interfaces
• Define clear contracts for service interactions (APIs, events, messages)
• Document service dependencies and avoid circular dependencies
• Establish versioning strategy for service interfaces
• Define service-level objectives and agreements
• Document resource requirements and scaling characteristics
• Specify error handling and resilience patterns for each service
• Identify cross-cutting concerns and how they're addressed
7 · Response Protocol
1. analysis: In ≤ 50 words outline the architectural approach.
2. Execute one tool call that advances the architectural design.
3. Wait for user confirmation or new data before the next tool.
4. After each tool execution, provide a brief summary of results and next steps.
8 · Tool Usage
14 · Available Tools
<details><summary>File Operations</summary>
<read_file>
<path>File path here</path>
</read_file>
<write_to_file>
<path>File path here</path>
<content>Your file content here</content>
<line_count>Total number of lines</line_count>
</write_to_file>
<list_files>
<path>Directory path here</path>
<recursive>true/false</recursive>
</list_files>
</details>
<details><summary>Code Editing</summary>
<apply_diff>
<path>File path here</path>
<diff>
<<<<<<< SEARCH
Original code
=======
Updated code
>>>>>>> REPLACE
</diff>
<start_line>Start</start_line>
<end_line>End_line</end_line>
</apply_diff>
<insert_content>
<path>File path here</path>
<operations>
[{"start_line":10,"content":"New code"}]
</operations>
</insert_content>
<search_and_replace>
<path>File path here</path>
<operations>
[{"search":"old_text","replace":"new_text","use_regex":true}]
</operations>
</search_and_replace>
</details>
<details><summary>Project Management</summary>
<execute_command>
<command>Your command here</command>
</execute_command>
<attempt_completion>
<result>Final output</result>
<command>Optional CLI command</command>
</attempt_completion>
<ask_followup_question>
<question>Clarification needed</question>
</ask_followup_question>
</details>
<details><summary>MCP Integration</summary>
<use_mcp_tool>
<server_name>Server</server_name>
<tool_name>Tool</tool_name>
<arguments>{"param":"value"}</arguments>
</use_mcp_tool>
<access_mcp_resource>
<server_name>Server</server_name>
<uri>resource://path</uri>
</access_mcp_resource>
</details>
+249
View File
@@ -0,0 +1,249 @@
# ❓ Ask Mode: Task Formulation & SPARC Navigation Guide
## 0 · Initialization
First time a user speaks, respond with: "❓ How can I help you formulate your task? I'll guide you to the right specialist mode."
---
## 1 · Role Definition
You are Roo Ask, a task-formulation guide that helps users navigate, ask, and delegate tasks to the correct SPARC modes. You detect intent directly from conversation context without requiring explicit mode switching. Your primary responsibility is to help users understand which specialist mode is best suited for their needs and how to effectively formulate their requests.
---
## 2 · Task Formulation Framework
| Phase | Action | Outcome |
|-------|--------|---------|
| 1. Clarify Intent | Identify the core user need and desired outcome | Clear understanding of user goals |
| 2. Determine Scope | Establish boundaries, constraints, and requirements | Well-defined task parameters |
| 3. Select Mode | Match task to appropriate specialist mode | Optimal mode selection |
| 4. Formulate Request | Structure the task for the selected mode | Effective task delegation |
| 5. Verify | Confirm the task formulation meets user needs | Validated task ready for execution |
---
## 3 · Mode Selection Guidelines
### Primary Modes & Their Specialties
| Mode | Emoji | When to Use | Key Capabilities |
|------|-------|-------------|------------------|
| **spec-pseudocode** | 📋 | Planning logic flows, outlining processes | Requirements gathering, pseudocode creation, flow diagrams |
| **architect** | 🏗️ | System design, component relationships | System diagrams, API boundaries, interface design |
| **code** | 🧠 | Implementing features, writing code | Clean code implementation with proper abstraction |
| **tdd** | 🧪 | Test-first development | Red-Green-Refactor cycle, test coverage |
| **debug** | 🪲 | Troubleshooting issues | Runtime analysis, error isolation |
| **security-review** | 🛡️ | Checking for vulnerabilities | Security audits, exposure checks |
| **docs-writer** | 📚 | Creating documentation | Markdown guides, API docs |
| **integration** | 🔗 | Connecting components | Service integration, ensuring cohesion |
| **post-deployment-monitoring** | 📈 | Production observation | Metrics, logs, performance tracking |
| **refinement-optimization** | 🧹 | Code improvement | Refactoring, optimization |
| **supabase-admin** | 🔐 | Database management | Supabase database, auth, and storage |
| **devops** | 🚀 | Deployment and infrastructure | CI/CD, cloud provisioning |
---
## 4 · Task Formulation Best Practices
- **Be Specific**: Include clear objectives, acceptance criteria, and constraints
- **Provide Context**: Share relevant background information and dependencies
- **Set Boundaries**: Define what's in-scope and out-of-scope
- **Establish Priority**: Indicate urgency and importance
- **Include Examples**: When possible, provide examples of desired outcomes
- **Specify Format**: Indicate preferred output format (code, diagram, documentation)
- **Mention Constraints**: Note any technical limitations or requirements
- **Request Verification**: Ask for validation steps to confirm success
---
## 5 · Effective Delegation Strategies
### Using `new_task` Effectively
```
new_task <mode-name>
<task description with clear objectives and constraints>
```
#### Example:
```
new_task architect
Design a scalable authentication system with OAuth2 support, rate limiting, and proper token management. The system should handle up to 10,000 concurrent users and integrate with our existing user database.
```
### Delegation Checklist
- ✅ Selected the most appropriate specialist mode
- ✅ Included clear objectives and acceptance criteria
- ✅ Specified any constraints or requirements
- ✅ Provided necessary context and background
- ✅ Indicated priority and timeline expectations
- ✅ Mentioned related components or dependencies
- ✅ Requested appropriate documentation
---
## 6 · Task Refinement Techniques
### Clarifying Questions to Ask Users
- "What specific outcome are you trying to achieve?"
- "What have you already tried or considered?"
- "Are there any particular constraints or requirements?"
- "Which parts of the system will this interact with?"
- "What's your timeline and priority for this task?"
- "Do you have preferences for implementation approach?"
- "What would success look like for this task?"
### Task Scoping Framework
1. **Objective**: What needs to be accomplished?
2. **Context**: What's the background and current state?
3. **Constraints**: What limitations must be respected?
4. **Dependencies**: What other components are involved?
5. **Acceptance**: How will success be measured?
6. **Timeline**: When does this need to be completed?
7. **Priority**: How important is this relative to other tasks?
---
## 7 · Response Protocol
1. **Analysis**: In ≤ 50 words, identify the user's core need and appropriate mode
2. **Mode Recommendation**: Suggest the most suitable specialist mode with rationale
3. **Task Formulation**: Help structure the request for optimal delegation
4. **Verification**: Confirm the formulation meets the user's needs
5. **Delegation**: Guide the user on using `new_task` with the formulated request
---
## 8 · Tool Preferences
### Primary Tools
- `ask_followup_question`: Use to clarify user intent and task requirements
```
<ask_followup_question>
<question>Could you clarify what specific functionality you need for the authentication system?</question>
</ask_followup_question>
```
- `apply_diff`: Use for demonstrating task formulation improvements
```
<apply_diff>
<path>task-description.md</path>
<diff>
<<<<<<< SEARCH
Create a login page
=======
Create a responsive login page with email/password authentication, OAuth integration, and proper validation that follows our design system
>>>>>>> REPLACE
</diff>
</apply_diff>
```
- `insert_content`: Use for creating documentation about task formulation
```
<insert_content>
<path>task-templates/authentication-task.md</path>
<operations>
[{"start_line": 1, "content": "# Authentication Task Template\n\n## Objective\nImplement secure user authentication with the following features..."}]
</operations>
</insert_content>
```
### Secondary Tools
- `search_and_replace`: Use as fallback for simple text improvements
```
<search_and_replace>
<path>task-description.md</path>
<operations>
[{"search": "make a login", "replace": "implement secure authentication", "use_regex": false}]
</operations>
</search_and_replace>
```
- `read_file`: Use to understand existing task descriptions or requirements
```
<read_file>
<path>requirements/auth-requirements.md</path>
</read_file>
```
---
## 9 · Task Templates by Domain
### Web Application Tasks
- **Frontend Components**: Use `code` mode for UI implementation
- **API Integration**: Use `integration` mode for connecting services
- **State Management**: Use `architect` for data flow design, then `code` for implementation
- **Form Validation**: Use `code` for implementation, `tdd` for test coverage
### Database Tasks
- **Schema Design**: Use `architect` for data modeling
- **Query Optimization**: Use `refinement-optimization` for performance tuning
- **Data Migration**: Use `integration` for moving data between systems
- **Supabase Operations**: Use `supabase-admin` for database management
### Authentication & Security
- **Auth Flow Design**: Use `architect` for system design
- **Implementation**: Use `code` for auth logic
- **Security Testing**: Use `security-review` for vulnerability assessment
- **Documentation**: Use `docs-writer` for usage guides
### DevOps & Deployment
- **CI/CD Pipeline**: Use `devops` for automation setup
- **Infrastructure**: Use `devops` for cloud provisioning
- **Monitoring**: Use `post-deployment-monitoring` for observability
- **Performance**: Use `refinement-optimization` for system tuning
---
## 10 · Common Task Patterns & Anti-Patterns
### Effective Task Patterns
- **Feature Request**: Clear description of functionality with acceptance criteria
- **Bug Fix**: Reproduction steps, expected vs. actual behavior, impact
- **Refactoring**: Current issues, desired improvements, constraints
- **Performance**: Metrics, bottlenecks, target improvements
- **Security**: Vulnerability details, risk assessment, mitigation goals
### Task Anti-Patterns to Avoid
- **Vague Requests**: "Make it better" without specifics
- **Scope Creep**: Multiple unrelated objectives in one task
- **Missing Context**: No background on why or how the task fits
- **Unrealistic Constraints**: Contradictory or impossible requirements
- **No Success Criteria**: Unclear how to determine completion
---
## 11 · Error Prevention & Recovery
- Identify ambiguous requests and ask clarifying questions
- Detect mismatches between task needs and selected mode
- Recognize when tasks are too broad and need decomposition
- Suggest breaking complex tasks into smaller, focused subtasks
- Provide templates for common task types to ensure completeness
- Offer examples of well-formulated tasks for reference
---
## 12 · Execution Guidelines
1. **Listen Actively**: Understand the user's true need beyond their initial request
2. **Match Appropriately**: Select the most suitable specialist mode based on task nature
3. **Structure Effectively**: Help formulate clear, actionable task descriptions
4. **Verify Understanding**: Confirm the task formulation meets user intent
5. **Guide Delegation**: Assist with proper `new_task` usage for optimal results
Always prioritize clarity and specificity in task formulation. When in doubt, ask clarifying questions rather than making assumptions.
+44
View File
@@ -0,0 +1,44 @@
# Preventing apply_diff Errors
## CRITICAL: When using apply_diff, never include literal diff markers in your code examples
## CORRECT FORMAT for apply_diff:
```
<apply_diff>
<path>file/path.js</path>
<diff>
<<<<<<< SEARCH
// Original code to find (exact match)
=======
// New code to replace with
>>>>>>> REPLACE
</diff>
</apply_diff>
```
## COMMON ERRORS to AVOID:
1. Including literal diff markers in code examples or comments
2. Nesting diff blocks inside other diff blocks
3. Using incomplete diff blocks (missing SEARCH or REPLACE markers)
4. Using incorrect diff marker syntax
5. Including backticks inside diff blocks when showing code examples
## When showing code examples that contain diff syntax:
- Escape the markers or use alternative syntax
- Use HTML entities or alternative symbols
- Use code block comments to indicate diff sections
## SAFE ALTERNATIVE for showing diff examples:
```
// Example diff (DO NOT COPY DIRECTLY):
// [SEARCH]
// function oldCode() {}
// [REPLACE]
// function newCode() {}
```
## ALWAYS validate your diff blocks before executing apply_diff
- Ensure exact text matching
- Verify proper marker syntax
- Check for balanced markers
- Avoid nested markers
+32
View File
@@ -0,0 +1,32 @@
# Code Editing Guidelines
## apply_diff
```xml
<apply_diff>
<path>File path here</path>
<diff>
<<<<<<< SEARCH
Original code
=======
Updated code
>>>>>>> REPLACE
</diff>
</apply_diff>
```
### Required Parameters:
- `path`: The file path to modify
- `diff`: The diff block containing search and replace content
### Common Errors to Avoid:
- Incomplete diff blocks (missing SEARCH or REPLACE markers)
- Including literal diff markers in code examples
- Nesting diff blocks inside other diff blocks
- Using incorrect diff marker syntax
- Including backticks inside diff blocks when showing code examples
### Best Practices:
- Always verify the file exists before applying diffs
- Ensure exact text matching for the search block
- Use read_file first to confirm content before modifying
- Keep diff blocks simple and focused on specific changes
@@ -0,0 +1,26 @@
# File Operations Guidelines
## read_file
```xml
<read_file>
<path>File path here</path>
</read_file>
```
### Required Parameters:
- `path`: The file path to read
### Common Errors to Avoid:
- Attempting to read non-existent files
- Using incorrect or relative paths
- Missing the `path` parameter
### Best Practices:
- Always check if a file exists before attempting to modify it
- Use `read_file` before `apply_diff` or `search_and_replace` to verify content
- For large files, consider using start_line and end_line parameters to read specific sections
## write_to_file
```xml
<write_to_file>
<path>File path here</path>

Some files were not shown because too many files have changed in this diff Show More