Content
# Ruflo Hub — Docker
A central MCP hub for your team: it takes the one genuinely-working part of the Ruflo CLI — its **memory layer** (real embeddings + HNSW + SQLite + auto-memory) — and makes it **shared and networked over HTTP**, so Claude Code sessions across a whole team share one persistent memory. A statusline backed by remote data comes along for free. Active memory is local sql.js; PostgreSQL (pgvector) is an **optional** backup for `ruflo ruvector import/export`.
> **What this is, in one line:** the valuable, working ~1% of ruflo (memory) — extracted, made team-shareable, with the swarm/neural "theater" left out. See [What this actually is](#what-this-actually-is) before you judge it by ruflo's marketing.
> 🇷🇺 Russian version: [docs/ru/README.md](docs/ru/README.md)
> **Guides:**
> - [Use cases](docs/use-cases.md) — scenarios for personal / team / multi-team use, pattern transfer between instances
> - [Ruflo usage guide](docs/ruflo-usage-guide.md) — practical distillation of the official README: what hooks do, which MCP tools you actually need, skills, 3-tier routing
> - [Swarm management](docs/swarm-management.md) — swarm operations: concept, lifecycle, ruflo@3.5.x quirks
> - [Multi-project work with ruflo](docs/ruflo-multiproject-guide.md) — knowledge transfer, task coordination, claims, hive-mind
```
Ruflo MCP (stdio) → Express proxy (Streamable HTTP) → port 3000
↕
sql.js (/app/.swarm/memory.db) ← active memory
↕ (optional, manual commands)
PostgreSQL + pgvector (RuVector) ← archive/bridge
```
## What this actually is
Be skeptical of ruflo's marketing — and so are we. Independent audits (and our own teardown) show that **most of ruflo's 300+ "MCP tools" are non-functional stubs**: `agent_spawn` just writes a Map entry, `swarm_init` leaves `agentCount: 0`, "hive-mind" is a `claude` subprocess with a role-play prompt, `neural_train` returns `Math.random()`. The 100+ "agents" are markdown. As an *agent-swarm orchestrator*, ruflo is largely theater.
**One part is genuinely real, and it's the part we use:** the memory layer — real `all-MiniLM-L6-v2` embeddings, a real HNSW index, real SQLite persistence, plus the auto-memory hook. `ruflo-hub` is a thin wrapper that exposes **only that layer** over HTTP and bridges it into Claude Code. We don't ship the swarm/neural theater as a feature, and we don't load 300 stub tool-definitions into your context as a selling point.
So judge this project as exactly one thing: **shared, networked, persistent memory for Claude Code** — not a swarm framework.
### Honesty notes (memory & safety)
- **The memory layer had a real leak.** sql.js's WASM in-memory filesystem (MEMFS) hoards one full DB image per database open — a prod instance grew to ~36 GB RSS over six weeks. We contain it with an **RSS watchdog** that gracefully respawns the child past a RAM threshold (`RUFLO_CHILD_MAX_RSS_MB`, default 3000) and patch the root cause at build time. Full heap-snapshot writeup: [`ruvnet/ruflo#2432`](https://github.com/ruvnet/ruflo/issues/2432).
- **Security history (important):** ruflo [issue #1375](https://github.com/ruvnet/ruflo/issues/1375) reported a malicious obfuscated preinstall script and a hidden prompt-injection in MCP tool descriptions — **in old versions (3.1.0-alpha.55 – 3.5.2)**. Because this hub installs the package and serves tool descriptions to clients, we verified the version we ship (3.12.4): no preinstall scripts, and all 302 tool descriptions are clean. Treated as remediated in current versions — but **pin your version and verify yourself.**
- **Backup is WAL-safe by volume.** `memory.db` is SQLite in WAL mode; the volume `tar` (below) captures `memory.db` + `-wal` + `-shm` together. Copying `memory.db` alone yields `database disk image is malformed`.
## Quick start
### With PostgreSQL (full mode)
```bash
cp .env.example .env
# Edit .env — change POSTGRES_PASSWORD
docker compose up -d
```
`.env` must contain the line `COMPOSE_PROFILES=pg` (it's in `.env.example` by default) — this enables the `ruflo-db` service.
### Lean mode (without PostgreSQL)
```bash
cp .env.example .env
# Comment out or remove the COMPOSE_PROFILES=pg line
docker compose up -d
```
Only the ruflo services will start. Memory will be stored in sql.js (`/app/.swarm/memory.db`), persistent via a volume. Downside: `ruflo ruvector import/export` commands are unavailable — for transferring patterns between instances see alternatives in [docs/use-cases.md](docs/use-cases.md).
Server: `http://localhost:3000/mcp`
## Embedding as a service
The `jazzmax/ruflo-hub` image can be added to any existing `docker-compose.yml`.
> ### ⚠ Memory persistence — read this before deploying
>
> The active memory store (`/app/.swarm/memory.db`, sql.js + HNSW) lives **inside the container's filesystem by default**. If you run `docker compose pull && up -d` (or otherwise recreate the container) without a named volume mounted at `/app/.swarm`, **your entire memory is wiped**. PostgreSQL is *not* a substitute — it's an optional archive used only by `ruflo ruvector import/export`.
>
> Always declare the memory volumes **before the first `docker compose up -d`**:
>
> ```yaml
> services:
> ruflo:
> # ...
> volumes:
> - ruflo-memory:/app/.swarm # memory.db + WAL + stderr log
> - ruflo-state:/app/.claude-flow # config + system_health stubs
>
> volumes:
> ruflo-pgdata:
> ruflo-memory:
> ruflo-state:
> ```
>
> All three examples below already include these volumes. If you are migrating an *existing* deployment that has no volume on `/app/.swarm`, see [Migrating an existing deployment to volumes](#migrating-an-existing-deployment-to-volumes) below — there is a procedure to copy live data into a new volume without losing it.
### Variant A: with your own PostgreSQL (pgvector)
If your project doesn't yet have PostgreSQL with pgvector:
```yaml
services:
# ... your services ...
ruflo:
image: jazzmax/ruflo-hub:latest
restart: unless-stopped
ports:
- "3000:3000"
environment:
RUFLO_PORT: 3000
POSTGRES_HOST: ruflo-db
POSTGRES_PORT: 5432
POSTGRES_DB: ruflo
POSTGRES_USER: ruflo
POSTGRES_PASSWORD: changeme
volumes:
- ruflo-memory:/app/.swarm
- ruflo-state:/app/.claude-flow
depends_on:
ruflo-db:
condition: service_healthy
ruflo-db:
image: pgvector/pgvector:pg17
restart: unless-stopped
environment:
POSTGRES_DB: ruflo
POSTGRES_USER: ruflo
POSTGRES_PASSWORD: changeme
volumes:
- ruflo-pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ruflo"]
interval: 5s
timeout: 3s
retries: 10
volumes:
ruflo-pgdata:
ruflo-memory:
ruflo-state:
```
### Variant B: connect to an existing PostgreSQL
If PostgreSQL (with pgvector) already exists in the project:
```yaml
services:
# ... your existing postgres ...
# postgres:
# image: pgvector/pgvector:pg17
# ...
ruflo:
image: jazzmax/ruflo-hub:latest
restart: unless-stopped
ports:
- "3000:3000"
environment:
RUFLO_PORT: 3000
POSTGRES_HOST: postgres # name of your PostgreSQL service
POSTGRES_PORT: 5432
POSTGRES_DB: ruflo # a separate database for ruflo
POSTGRES_USER: ruflo
POSTGRES_PASSWORD: changeme
volumes:
- ruflo-memory:/app/.swarm
- ruflo-state:/app/.claude-flow
depends_on:
postgres:
condition: service_healthy
volumes:
ruflo-memory:
ruflo-state:
```
> PostgreSQL must have the pgvector extension. The `pgvector/pgvector:pg17` image ships with it.
> A plain `postgres:17` without pgvector will not work.
### Variant C: external PostgreSQL (outside Docker)
```yaml
services:
ruflo:
image: jazzmax/ruflo-hub:latest
restart: unless-stopped
ports:
- "3000:3000"
environment:
RUFLO_PORT: 3000
POSTGRES_HOST: 192.168.1.100 # IP of your server
POSTGRES_PORT: 5432
POSTGRES_DB: ruflo
POSTGRES_USER: ruflo
POSTGRES_PASSWORD: changeme
volumes:
- ruflo-memory:/app/.swarm
- ruflo-state:/app/.claude-flow
volumes:
ruflo-memory:
ruflo-state:
```
### Healthcheck
The image has a built-in healthcheck. Other services can depend on ruflo:
```yaml
services:
my-app:
image: my-app:latest
depends_on:
ruflo:
condition: service_healthy
```
### Multiple teams — multiple instances
```yaml
services:
ruflo-team-alpha:
image: jazzmax/ruflo-hub:latest
ports:
- "3001:3001"
environment:
RUFLO_PORT: 3001
POSTGRES_HOST: ruflo-db
POSTGRES_DB: ruflo_alpha
POSTGRES_USER: ruflo
POSTGRES_PASSWORD: changeme
ruflo-team-beta:
image: jazzmax/ruflo-hub:latest
ports:
- "3002:3002"
environment:
RUFLO_PORT: 3002
POSTGRES_HOST: ruflo-db
POSTGRES_DB: ruflo_beta
POSTGRES_USER: ruflo
POSTGRES_PASSWORD: changeme
ruflo-db:
image: pgvector/pgvector:pg17
environment:
POSTGRES_USER: ruflo
POSTGRES_PASSWORD: changeme
volumes:
- ruflo-pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ruflo"]
interval: 5s
timeout: 3s
retries: 10
volumes:
ruflo-pgdata:
```
> With a shared PostgreSQL, each instance uses its own database (`ruflo_alpha`, `ruflo_beta`). Databases are created automatically on the first RuVector startup.
## Connecting clients
### Automatic setup (recommended)
A single command from the project root:
```bash
curl "http://your-server:3000/setup?token=YOUR_TOKEN&name=ruflo-team" | bash
```
Or with an explicit project path:
```bash
curl "http://your-server:3000/setup?token=YOUR_TOKEN&name=ruflo-team" | bash -s /path/to/project
```
#### `/setup` parameters
| Parameter | Default | Description |
|-----------|---------|-------------|
| `token` | — | Bearer token for authorization (the server's `MCP_AUTH_TOKEN` value) |
| `name` | `ruflo` | MCP server name in `.mcp.json` (determines the tool prefix: `mcp__<name>__*`) |
| `skills` | `1` | Install the skills/agents/commands bundle. `0` (`false`/`no`/`off`) disables it |
#### What the script does
1. Downloads hooks from the server (`auto-memory-hook.mjs`, `hook-handler.cjs`, `statusline.cjs`) into `.claude/helpers/`
2. Downloads and unpacks the `skills` + `agents` + `commands` bundle into `.claude/` (existing files are not overwritten — customizations are preserved; disable with `?skills=0`)
3. Creates `.claude-flow/ruflo.json` with the server URL and token (for the memory bridge)
4. Creates or amends `.mcp.json` with the MCP connection and authorization header
5. Creates `.claude/settings.json` with hook configuration (if the file doesn't already exist)
6. Verifies connectivity to the server
#### Examples
```bash
# Minimal (no auth, default name "ruflo")
curl http://192.168.1.100:3000/setup | bash
# With authorization
curl "http://192.168.1.100:3000/setup?token=572fd23e-ae2e-4e3b-9ea5-59e7a84c09a7" | bash
# Custom name per team
curl "http://192.168.1.100:3001/setup?token=TOKEN_A&name=ruflo-alpha" | bash
curl "http://192.168.1.100:3002/setup?token=TOKEN_B&name=ruflo-beta" | bash
# MCP bridge only, no skills/agents (legacy behavior)
curl "http://192.168.1.100:3000/setup?token=TOKEN&skills=0" | bash
```
#### ⚠️ Server on the same machine — use a hostname, not an IP
If ruflo-hub is running **on your laptop/desktop**, don't pin to an IP — it changes when you switch Wi-Fi/VPN. Use your machine's mDNS name (macOS and most Linux distros support `.local` out of the box via Bonjour/Avahi):
```bash
# macOS/Linux — hostname substitution
curl "http://$(hostname):3201/setup?token=TOKEN" | bash
# Explicit:
curl "http://MacBook-Pro-3.local:3201/setup?token=TOKEN" | bash
```
The same rule applies to `.claude-flow/ruflo.json` and `.mcp.json` — prefer storing `http://MacBook-Pro-3.local:3201/mcp` instead of an IP. Then the client keeps working across any network change.
**When `.local` is NOT suitable:**
- Clients outside the local network (another team's VPN, a remote VPS) — `hostname.local` won't resolve for them. You'll need public DNS (`ruflo.mycompany.com`) or a tunnel (Tailscale/Cloudflare Tunnel).
- Corporate networks with restrictive policies — Bonjour/mDNS may be disabled by IT. Check with `ping $(hostname)` from a client machine.
### Updating the bundle in an already-configured project
When new skills/agents/commands appear in the hub (or they get updated in the Docker image), you can update only the bundle — without re-running `/setup`, which would overwrite your configs:
```bash
# Current directory
curl http://your-server:3000/update-bundle | bash
# With an explicit project path
curl http://your-server:3000/update-bundle | bash -s /path/to/project
# Force-overwrite existing files
curl "http://your-server:3000/update-bundle?force=1" | bash
```
By default `tar -xzkf` (the `-k` flag) doesn't touch existing files — it only adds missing ones. With `?force=1` it's a full overwrite. Unlike `/setup`, this endpoint does not create `.claude-flow/ruflo.json`, `.mcp.json`, or `settings.json` — bundle only.
Don't forget to **restart Claude Code** in the project — skills load at SessionStart.
### Manual MCP connection
If you only need MCP without hooks or the memory bridge:
**Claude Code CLI:**
```bash
claude mcp add --transport http \
-H "Authorization: Bearer YOUR_TOKEN" \
ruflo-team http://your-server:3000/mcp
```
**Claude Desktop / VS Code / Cursor / JetBrains** (`.mcp.json`):
```json
{
"mcpServers": {
"ruflo-team": {
"type": "http",
"url": "http://your-server:3000/mcp",
"headers": {
"Authorization": "Bearer YOUR_TOKEN"
}
}
}
}
```
> An MCP connection exposes ruflo's tool surface, but in practice the tools worth calling are the **memory** ones (`memory_store`, `memory_search`, `memory_list`, …) — the swarm/neural/agent tools are mostly stubs (see [What this actually is](#what-this-actually-is)). Automatic setup via `/setup` additionally wires the **memory bridge** — pattern synchronization between Claude Code sessions.
## API endpoints
| Method | URL | Description |
|--------|-----|-------------|
| POST | `/mcp` | JSON-RPC proxy to ruflo MCP (main endpoint) |
| GET / DELETE | `/mcp` | Returns `405 Method Not Allowed` (MCP is POST-only) |
| GET | `/health` | Server status (`{"status":"ok","tools":302, ...}`) — includes RSS-watchdog stats (`childRssMB`, `childRespawnCount`) |
| GET | `/stats` | Statusline summary: vectors, namespaces, `dbSizeKB`, swarm state, intelligence score |
| GET | `/setup` | Shell script for automatic project setup |
| GET | `/update-bundle` | Shell script for bundle-only updates (skills+agents+commands) |
| GET | `/bundle.tar.gz` | Tar.gz archive of the bundle (used by `/setup` and `/update-bundle`) |
| GET | `/templates` | List of available templates |
| GET | `/templates/:name` | Download a specific template |
| GET | `/.well-known/oauth-authorization-server` | OAuth discovery stub (returns 404 so clients fall back to no-auth) |
| GET | `/.well-known/oauth-protected-resource` | OAuth discovery stub (returns 404) |
| POST | `/register` | OAuth dynamic-client stub (returns 404) |
### POST /mcp — JSON-RPC
```bash
# Tool invocation
curl -X POST http://your-server:3000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"memory_store","arguments":{"key":"my-pattern","value":"pattern content","namespace":"my-project"}},"id":1}'
# Memory search
curl -X POST http://your-server:3000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"memory_search","arguments":{"query":"my search"}},"id":1}'
# List tools
curl -X POST http://your-server:3000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/list","id":1}'
```
### Authentication
If `MCP_AUTH_TOKEN` is set, all requests to `/mcp` require the header:
```
Authorization: Bearer <token>
```
The `/health`, `/stats`, `/setup`, `/update-bundle`, `/bundle.tar.gz`, `/templates`, and the OAuth discovery stubs are available without authorization.
## Memory Bridge
The bridge automatically synchronizes knowledge between Claude Code sessions and the ruflo server.
```
┌─────────────────────┐ ┌──────────────┐
│ Claude Code │ │ Ruflo Server │
│ │ HTTP │ │
│ SessionStart ──────┼────────→│ memory_list │
│ (import) │←────────┼ memory_get │
│ │ │ │
│ Stop ──────────────┼────────→│ memory_store│
│ (sync) │ │ │
└─────────────────────┘ └──────────────┘
```
**At session start** (`auto-memory-hook.mjs import`):
- loads project patterns from the namespace named after the project directory
- loads shared patterns (common to all projects)
- emits them into the Claude Code session context
**At stop** (`auto-memory-hook.mjs sync`):
- reads Claude auto-memory files (`~/.claude/projects/.../memory/*.md`)
- pushes feedback and project entries to ruflo-hub
- available in the next session and from other projects
### Manual control
```bash
# Bridge status
node .claude/helpers/auto-memory-hook.mjs status
# Force sync
node .claude/helpers/auto-memory-hook.mjs sync
# Load patterns
node .claude/helpers/auto-memory-hook.mjs import
```
## Templates (templates/)
Files in `templates/` are served via `/templates/:name` and used by the `/setup` script:
| File | Purpose |
|------|---------|
| `auto-memory-hook.mjs` | Memory bridge — HTTP client for ruflo-hub |
| `hook-handler.cjs` | Claude Code hook handler (routing, status, edit tracking) |
| `statusline.cjs` | Statusline generator (git, model, context, cost, swarm) |
| `settings.json` | Template for `.claude/settings.json` with hook configuration |
### Server URL resolution
`auto-memory-hook.mjs` resolves the server URL in this priority order:
1. The `RUFLO_URL` environment variable
2. The `.claude-flow/ruflo.json` file (created by `/setup`)
3. Auto-discovery from a sibling `ruflo-hub/` project
4. Fallback: `http://localhost:3000/mcp`
## Environment variables
| Variable | Default | Description |
|----------|---------|-------------|
| `RUFLO_PORT` | `3000` | MCP server port |
| `POSTGRES_HOST` | `localhost` | PostgreSQL host |
| `POSTGRES_PORT` | `5432` | PostgreSQL port |
| `POSTGRES_DB` | `ruflo` | Database name |
| `POSTGRES_USER` | `ruflo` | User |
| `POSTGRES_PASSWORD` | `ruflo` | Password (change it!) |
| `MCP_AUTH_TOKEN` | — | Bearer token for authorization (if empty — no auth) |
## Backup
The active memory lives in `/app/.swarm/memory.db` inside the ruflo container, mounted from the `<service>-memory` volume. **That volume is what you back up — `pg_dump` of the PostgreSQL database is not enough**, because the regular `memory_store` / `memory_search` tools write into sql.js, not into PostgreSQL. The `claude_flow.*` tables in PostgreSQL are used only by the optional `ruflo ruvector import/export` flow and may legitimately be empty.
```bash
# Backup the memory volume (active memory + HNSW indexes)
docker run --rm -v ruflo-server_ruflo-memory:/d -v "$PWD":/b alpine \
tar czf /b/ruflo-memory.tgz -C /d .
# Restore
docker run --rm -v ruflo-server_ruflo-memory:/d -v "$PWD":/b alpine \
sh -c "rm -rf /d/* && tar xzf /b/ruflo-memory.tgz -C /d"
# Optional — PostgreSQL dump (only if you actively use ruvector import/export)
docker exec <postgres-container> pg_dump -U ruflo ruflo > backup.sql
cat backup.sql | docker exec -i <postgres-container> psql -U ruflo ruflo
```
### Migrating an existing deployment to volumes
If you deployed ruflo-hub before adding the `ruflo-memory` / `ruflo-state` volumes, your `/app/.swarm/memory.db` lives inside the container's R/W layer and **the next `docker compose up -d` will erase it**. Migrate live data into a named volume *before* recreating the container.
Run this on the host where ruflo-hub lives. Replace `<service>` with your project name (e.g. `ruflo-hub`) — Compose prefixes volume names with it.
```bash
cd /path/to/ruflo-hub
SNAP=/tmp/ruflo-snap-$(date +%s)
mkdir -p $SNAP/swarm $SNAP/claude-flow
# 1. Snapshot live data while the container is still running (small dataset)
docker cp ruflo:/app/.swarm/. $SNAP/swarm/
docker cp ruflo:/app/.claude-flow/. $SNAP/claude-flow/
# 2. Graceful stop so SQLite checkpoints the WAL, then take a final snapshot
docker compose stop ruflo
docker cp ruflo:/app/.swarm/. $SNAP/swarm/
docker cp ruflo:/app/.claude-flow/. $SNAP/claude-flow/
# 3. Create the named volumes and load the snapshot
docker volume create <service>_ruflo-memory
docker volume create <service>_ruflo-state
docker run --rm -v <service>_ruflo-memory:/dst -v $SNAP/swarm:/src alpine \
sh -c "rm -rf /dst/* && cp -a /src/. /dst/"
docker run --rm -v <service>_ruflo-state:/dst -v $SNAP/claude-flow:/src alpine \
sh -c "rm -rf /dst/* && cp -a /src/. /dst/"
# 4. Add the volume mappings to docker-compose.yml (see the warning above for the
# exact YAML), then recreate the container
docker compose up -d ruflo
# 5. Verify
docker inspect ruflo --format '{{range .Mounts}}{{.Type}} {{.Source}} -> {{.Destination}}{{println}}{{end}}'
curl -s http://localhost:3000/health # state should be "ready"
# 6. Keep $SNAP for a few days as a safety net before deleting
```
## Operational notes
A few things that look broken but are normal — knowing them up front avoids unnecessary "fixes" that can cause data loss:
- **`system_health` may report `score: 20/100, unhealthy`.** The check looks for marker files at default paths (`./.claude-flow/memory/store.json`, `./.claude-flow/config.json`) and ignores the real backend at `/app/.swarm/memory.db`. The entrypoint creates empty marker files on startup so other Claude instances don't suggest "run memory init" — this is cosmetic only. Use `memory_stats` to see real storage.
- **Don't run `ruflo init` or `ruflo memory init` inside the container.** They would create a second store at the default path and split your data between two places. The container is preconfigured; the active store at `/app/.swarm/memory.db` already works.
- **`claude_flow.embeddings` in PostgreSQL is normally empty (0 rows).** That table is for the RuVector backend (1536-dim), but the regular memory tools write 768-dim ONNX embeddings into sql.js. The two backends are independent. PostgreSQL is touched only by `ruflo ruvector import/export`.
- **`memory_bridge_status: not-synced` is fine** if no project under `~/.claude/projects/*/memory/MEMORY.md` exists yet. The bridge has nothing to mirror; direct `memory_store` calls still work.
- **High CPU at idle** comes from background controllers (consolidation, causal graph, nightly learner). They run regardless of whether you've fed them data.
## Updating ruflo
The `ruflo` package is pinned in the image at build time.
**Image rebuild (recommended):**
```bash
# Locally
docker compose build --no-cache
docker compose up -d
# For Docker Hub
docker build --no-cache -t jazzmax/ruflo-hub:latest .
docker push jazzmax/ruflo-hub:latest
```
**Update inside the container (fast, doesn't survive a restart):**
```bash
docker exec <ruflo-container> npm install -g ruflo@latest
docker restart <ruflo-container>
```
## Docker Hub
```bash
docker pull jazzmax/ruflo-hub:latest # rolling: every push to main
docker pull jazzmax/ruflo-hub:1 # major: latest 1.x.x
docker pull jazzmax/ruflo-hub:1.1 # minor: latest 1.1.x
docker pull jazzmax/ruflo-hub:1.1.0 # exact pin
docker pull jazzmax/ruflo-hub:<git-sha> # any commit, for trace/rollback
```
Versioned tags are published when you push a `vX.Y.Z` git tag (see Release process). `:latest` only moves on `main` pushes / weekly rebuilds — never on tag pushes — so pinning to `:1`/`:1.1` stays stable through patch releases.
## Release process
Versions follow [SemVer](https://semver.org/). Notable changes are recorded in [`CHANGELOG.md`](CHANGELOG.md).
```bash
# 1. Update CHANGELOG.md and bump package.json version (e.g. 1.1.0 → 1.2.0)
# 2. Commit
git commit -am "chore: release v1.2.0"
git push origin main
# 3. Tag the release commit and push
git tag v1.2.0
git push origin v1.2.0
```
The `v*.*.*` tag triggers GitHub Actions to publish `jazzmax/ruflo-hub:1.2.0`, `:1.2`, `:1`, and `:<sha>` to Docker Hub.
## Build from source
```bash
git clone https://github.com/jazz-max/ruflo-hub.git
cd ruflo-hub
docker build -t jazzmax/ruflo-hub:latest .
docker push jazzmax/ruflo-hub:latest
```
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available