Show & tell: ruflo-hub — I wanted my whole team (and all my machines) to share one ruflo brain, so I wrapped it in HTTP #2433
jazz-max
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Hey ruvnet & everyone 👋
First, thank you for ruflo — it genuinely changed how I work. The memory + intelligence layer is the thing I didn't know I needed, and now I can't go back. This post is half show-and-tell, half "here's what I learned the hard way," and one honest roadmap question at the end.
The itch
I run Claude across a few places — laptop, desktop, a couple of projects on a server. Each one spun up its own
ruflo mcp start, which meant each had its own memory. My laptop didn't know what my server-side sessions had learned. That broke the magic a little: the whole point of the memory layer is that it remembers, and mine was fragmented across processes.ruflo mcpis stdio-only, so there was no obvious way to say "everyone, talk to this one ruflo." So I built ruflo-hub: a small Docker wrapper that puts an Express + Streamable-HTTP proxy in front of a single long-livedruflo mcp start. Now every client connects over HTTP (type: "http") to one instance with one sharedmemory.db:One brain, many clients. (And multi-instance if you want — several hubs on different ports sharing one Postgres, namespaced per project.) It's been running my team's setup for weeks.
What I learned the hard way (maybe useful to you or others)
Running it 24/7 surfaced some sharp edges. Sharing them in the spirit of giving back, not complaining — every one of these taught me something:
heapTotalwas a flat ~24 MB). It was nativearrayBuffers: the sql.js Emscripten MEMFS quietly accumulatesdbfile_*files — roughly one fullmemory.dbimage per DB open — becausecreateDatabase()re-loads the DB into a freshSQL.Databasewithoutclose(), and GC of the wrapper never frees the MEMFS file. A heap-snapshot retainer trace nailed it; full write-up in Unbounded native memory leak: orphaned sql.js MEMFSdbfile_*files (~11 MB each) accumulate per database open #2432. I contain it with an RSS watchdog (graceful child respawn) and patch the root at build time (per-path backend cache).ruflo mcp startfor every concurrent request that hit "Not connected" — 100+ orphaned children and gigabytes over a few days. Killing the old child before spawning a new one fixed it.memory_storecrash. On a clean container it threwCannot convert undefined or null to objectuntil I learned to drop a.migrated-to-sqlitemarker next to a stubstore.json— otherwise the stub gets treated as a legacy dump and migration null-derefs.memory.dbis WAL-mode, and copying it without-wal/-shmreads back asdatabase disk image is malformed. (Ask me how I found out 😅 — a corrupted store and a long evening of heap snapshots and raw-page carving to get the data back.)None of this dimmed my enthusiasm — if anything, digging this deep made me appreciate how much ruflo is doing under the hood.
My one honest question
Is a native HTTP / Streamable transport anywhere on the roadmap — something like
ruflo mcp start --http? My proxy works, but the "one shared, networked ruflo" use case feels common enough that it might deserve to be first-class, and then folks wouldn't need a wrapper at all. If there's appetite for it, I'd love to help — I've already got the battle scars. 🙂Repo: https://github.com/jazz-max/ruflo-hub · related issue: #2432
Thanks again for building something worth wrapping. 🙏
Beta Was this translation helpful? Give feedback.
All reactions