Files
ruvnet__ruflo/v3/@claude-flow/cli/docker/Dockerfile
rUv dc8463872d feat(ADR-057): RVF native storage with security hardening (#1244)
* docs: add ADR-057 — RVF native storage backend to replace sql.js

Proposes replacing the 18MB sql.js WASM SQLite dependency with
RuVector Format (RVF) across @claude-flow/shared, memory, and
embeddings packages. Includes automatic and manual migration paths
for existing .db and .json files with full backward compatibility.

Key benefits: -18MB install size, 150x-12,500x faster vector search
via native HNSW, quantization support, crash-safe append-only format.

Co-Authored-By: claude-flow <ruv@ruv.net>

* docs: extend ADR-057 with RVF embedding provider, ruvLLM persistence, and progressive download

Add three major sections to ADR-057:

- Section 3A: RVF as 5th EmbeddingProvider (52KB WASM replaces 540MB
  agentic-flow for basic use cases). Updated auto-select hierarchy:
  rvf > agentic-flow > transformers > mock.

- Section 3B: ruvLLM learning persistence via RVF segments. SONA
  patterns (ReasoningBank), LoRA adapters, and EWC++ weights now
  survive process restarts. RuVectorProvider.searchMemory works
  offline via RVF without HTTP server.

- Section 10: Progressive download architecture. Replaces npm
  optionalDependencies (all-or-nothing 1.3GB) with on-demand
  capability downloads stored as .rvf files. 5 phases from 22MB
  core CLI to full LLM/CNN/GNN/kernel capabilities.

Implementation plan expanded from 5 to 8 phases. Testing strategy
updated with 11 new test cases covering the additions.

Co-Authored-By: claude-flow <ruv@ruv.net>

* feat: add optimized Docker images for Ruflo lite/full/workers

- Dockerfile: Multi-stage Alpine build with aggressive dependency pruning.
  Result: 324MB image, 0.6s startup (vs 1.3GB/35s baseline).
  Uses --omit=optional + explicit rm -rf of heavy transitive deps.

- Dockerfile.full: Full image variant with all optional dependencies
  including native compilation (onnxruntime-node, better-sqlite3).

- Dockerfile.headless: Updated from node:20 to node:22, claude-flow
  branding to ruflo, same prune strategy as lite.

- docker-compose.yml: Three profiles (lite, full, workers) with
  appropriate resource limits and health checks.

- .dockerignore: Excludes node_modules, tests, source maps, IDE
  configs, and secrets from build context.

Co-Authored-By: claude-flow <ruv@ruv.net>

* feat(ADR-057): implement RVF native storage backend across all packages

Replace sql.js (18MB WASM) with zero-dependency RVF format across
memory, events, embeddings, and learning subsystems. Pure TypeScript
fallback with optional native @ruvector/rvf acceleration.

New files:
- memory/rvf-backend.ts: IMemoryBackend impl with HNSW + binary persistence
- memory/hnsw-lite.ts: Lightweight HNSW graph for vector search
- memory/rvf-learning-store.ts: SONA pattern/LoRA/EWC/trajectory persistence
- memory/persistent-sona.ts: PersistentSonaCoordinator wrapping learning store
- shared/events/rvf-event-log.ts: Append-only event log (replaces EventStore)
- embeddings/rvf-embedding-cache.ts: Binary file embedding cache (FNV-1a keys)
- embeddings/rvf-embedding-service.ts: Hash-based embedding provider (<0.1ms)

Integrations:
- DatabaseProvider: 'rvf' added, auto-selected first (always available)
- EmbeddingProvider: 'rvf' added, auto-selected first in async factory
- All packages export new RVF types and classes

Tests: 163 passing (5 suites), validated in Docker (node:22-alpine)
- rvf-backend: 50 tests (CRUD, query, search, persistence, HNSW)
- rvf-event-log: 33 tests (append, replay, snapshots, crash recovery)
- rvf-embeddings: 30 tests (cache, service, determinism, normalization)
- rvf-learning-store: 31 tests (patterns, LoRA, EWC, trajectories)
- rvf-integration: 19 tests (provider selection, migration, concurrency)

Co-Authored-By: claude-flow <ruv@ruv.net>

* fix(ADR-057): harden RVF storage with security, performance, and migration

Security: atomic writes (tmp+rename) across all backends, path validation,
input validation at boundaries. Performance: persist lock prevents concurrent
flushes, stack overflow fix for large datasets, timer.unref() prevents hangs,
O(1) eviction lookup in embedding cache. New: bidirectional RVF migration
utility (JSON/SQLite/RVF), format v2 with backward compat, auto-persist
patterns and trajectories before eviction. Added HnswLite and RvfMigrator
exports. 193 tests passing, 0 TS errors.

Refs #1242

Co-Authored-By: claude-flow <ruv@ruv.net>

* fix: doctor version detection and init settings warnings (#1235, #1230)

doctor: Replace unreliable path-walking heuristic with import.meta.url
traversal to find the correct package.json. Removes stale npx cache
scanning that could report wrong versions. Fixes #1235.

init: Remove invalid TeammateIdle and TaskCompleted keys from generated
.claude/settings.json hooks section. These are not recognized by Claude
Code and caused warnings. Config remains available under the claudeFlow
namespace. Fixes #1230.

Co-Authored-By: claude-flow <ruv@ruv.net>

* fix(doctor): remove Windows-incompatible shell redirects, simplify root detection

- Remove fragile Windows root calculation (split on backslash); use
  dirname(dir) === dir instead which works on all platforms
- Remove 2>/dev/null from npm view command (fails on Windows cmd.exe);
  the catch block handles errors gracefully already

Co-Authored-By: claude-flow <ruv@ruv.net>

* security: harden RVF against crafted files and race conditions

- rvf-backend: validate dimensions (1-10000), validate RVF header
  structure and size before JSON.parse, guard persist interval
  against concurrent flushes
- rvf-embedding-cache: use random suffix for tmp files to prevent
  predictable-path attacks on multi-user systems
- rvf-event-log: add 100MB max payload size limit to prevent DoS
  from crafted event log files
- rvf-migration: add null byte and type validation on all paths

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-02-27 21:46:53 -05:00

129 lines
5.0 KiB
Docker

# Ruflo v3.5 — Optimized Production Image
# Multi-stage Alpine build with --omit=optional for <100MB image
#
# Build:
# docker build -t ruflo:lite -f v3/@claude-flow/cli/docker/Dockerfile .
#
# Run:
# docker run --rm ruflo:lite ruflo --version
# docker run --rm ruflo:lite ruflo doctor
# echo '{"jsonrpc":"2.0","id":1,"method":"initialize"}' | docker run --rm -i ruflo:lite
#
# Size comparison:
# npx ruflo@latest (cold): ~1.3GB, 914 packages, 35s startup
# ruflo:lite image: <100MB, ~60 packages, <5s startup
# ── Stage 1: Install ─────────────────────────────────────────────
FROM node:22-alpine AS build
RUN apk add --no-cache git
WORKDIR /install
# Install ruflo globally with --omit=optional to skip heavy deps.
# --ignore-scripts skips preinstall cache scanning (no-op in CI)
RUN npm install -g ruflo@latest \
--omit=optional \
--ignore-scripts \
--no-audit \
--no-fund \
&& npm cache clean --force
# Prune heavy optional transitive deps that npm still resolves.
# These are all optionalDependencies of @claude-flow/cli — the CLI
# works fine without them (graceful fallbacks built in).
# agentic-flow: 238MB (ONNX runtimes, OpenTelemetry, Anthropic SDK)
# @opentelemetry: 135MB (transitive via agentic-flow)
# onnxruntime-node/web: 158MB (ML inference, not needed for CLI)
# @anthropic-ai: 72MB (SDK, only needed when calling API directly)
# @xenova: 45MB (transformers.js, not needed for CLI)
# agentdb: 37MB (optional memory backend)
# @ruvector: 28MB (optional neural patterns)
# ruvector: 9MB (optional intelligence)
# onnx-proto: 22MB (protobuf for ONNX)
# tiktoken: 23MB (token counting, optional)
# @img: 16MB (image processing, not needed)
# better-sqlite3: 10MB (native, optional — sql.js used instead)
RUN GLOBAL_PREFIX=$(npm config get prefix) \
&& CLI_NM="${GLOBAL_PREFIX}/lib/node_modules/ruflo/node_modules" \
&& rm -rf \
"${CLI_NM}/agentic-flow" \
"${CLI_NM}/@opentelemetry" \
"${CLI_NM}/onnxruntime-node" \
"${CLI_NM}/onnxruntime-web" \
"${CLI_NM}/onnx-proto" \
"${CLI_NM}/@anthropic-ai" \
"${CLI_NM}/@xenova" \
"${CLI_NM}/agentdb" \
"${CLI_NM}/@ruvector" \
"${CLI_NM}/ruvector" \
"${CLI_NM}/tiktoken" \
"${CLI_NM}/@img" \
"${CLI_NM}/better-sqlite3" \
"${CLI_NM}/sharp" \
"${CLI_NM}/@google" \
&& rm -rf \
"${CLI_NM}/@claude-flow/embeddings" \
"${CLI_NM}/@claude-flow/memory" \
"${CLI_NM}/@claude-flow/codex" \
"${CLI_NM}/@claude-flow/guidance" \
"${CLI_NM}/@claude-flow/aidefence" \
"${CLI_NM}/@claude-flow/plugin-gastown-bridge" \
&& NESTED="${CLI_NM}/@claude-flow/cli/node_modules" \
&& rm -rf \
"${NESTED}/agentic-flow" \
"${NESTED}/@ruvector" \
"${NESTED}/agentdb" \
&& rm -rf \
"${CLI_NM}/ruvector-onnx-embeddings-wasm" \
"${CLI_NM}/ruvector-core-linux-x64-gnu" \
"${CLI_NM}/@claude-flow/neural" \
"${CLI_NM}/@grpc" \
"${CLI_NM}/gun"
# Stage the pruned install for the production image
RUN GLOBAL_PREFIX=$(npm config get prefix) \
&& mkdir -p /staged/lib /staged/bin \
&& cp -a "${GLOBAL_PREFIX}/lib/node_modules" /staged/lib/ \
&& cp -a "${GLOBAL_PREFIX}/bin/ruflo" /staged/bin/ 2>/dev/null || true \
&& cp -a "${GLOBAL_PREFIX}/bin/claude-flow" /staged/bin/ 2>/dev/null || true \
&& cp -a "${GLOBAL_PREFIX}/bin/cli" /staged/bin/ 2>/dev/null || true
# ── Stage 2: Production ──────────────────────────────────────────
FROM node:22-alpine AS production
# dumb-init for proper PID 1 signal handling
RUN apk add --no-cache dumb-init git bash ca-certificates curl
# Non-root user
RUN addgroup -g 1001 -S ruflo \
&& adduser -S -D -H -u 1001 -h /home/ruflo -s /bin/bash -G ruflo ruflo \
&& mkdir -p /home/ruflo/.claude-flow /workspace \
&& chown -R ruflo:ruflo /home/ruflo /workspace
# Copy only the global node_modules and bin links from build stage
COPY --from=build /staged/lib/node_modules /usr/local/lib/node_modules
COPY --from=build /staged/bin/ /usr/local/bin/
# Ensure bin symlinks point to the right place
RUN ln -sf /usr/local/lib/node_modules/ruflo/bin/ruflo.js /usr/local/bin/ruflo 2>/dev/null || true \
&& ln -sf /usr/local/lib/node_modules/@claude-flow/cli/bin/cli.js /usr/local/bin/claude-flow 2>/dev/null || true \
&& chmod +x /usr/local/bin/ruflo 2>/dev/null || true \
&& chmod +x /usr/local/bin/claude-flow 2>/dev/null || true
ENV NODE_ENV=production \
CLAUDE_FLOW_LOG_LEVEL=info \
HOME=/home/ruflo
# Healthcheck via CLI doctor (timeout after 10s)
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
CMD ruflo doctor --quiet || exit 1
USER ruflo
WORKDIR /workspace
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
# Default: start MCP server on stdio (most common Docker use case)
CMD ["ruflo", "mcp", "start"]