The Problem
Every time you start a new Claude Code session, it's a blank slate. It doesn't remember what you worked on yesterday, what decisions you made, or even who you are. File-based memory (~/.claude/projects/.../memory/) helps within a single machine, but it doesn't travel. If you work across multiple machines — a laptop, a remote server, a WSL instance — your context is fragmented.
We wanted Claude to remember everything, everywhere, automatically.
The Solution: fragRag
fragRag is a remote RAG (Retrieval-Augmented Generation) memory server built on:
- Supabase (PostgreSQL + pgvector) for storage and vector search
- Voyage AI (voyage-3 model) for semantic embeddings
- Cloudflare + Caddy for public HTTPS access
- MCP (Model Context Protocol) for Claude Code integration
It runs at fragrag.gitdiot.com and exposes tools like store_memory and search_memory that Claude can call directly. Memories are typed — facts, decisions, code patterns, architecture notes, user preferences — with importance scores and tags for filtering.
Claude Code (any machine)
↓ Streamable HTTP (https://fragrag.gitdiot.com/mcp)
↓ Bearer token auth
Cloudflare → Caddy → claude-memory server (port 3002)
↓ SQL + vector search
Supabase (PostgreSQL + pgvector) → Voyage AI embeddings
The Journey
Phase 1: The Server
Getting the MCP server running was its own adventure — documented in Debugging Across Machines. The short version: two Claude instances on different machines collaborated through Git commits to debug a transport issue where Express middleware was consuming the request stream before the MCP transport could read it.
Phase 2: The Skill That Didn't Work
With the server running, the next step was making it easy to use. An OMC (oh-my-claudecode) "learned skill" was created — fragrag/SKILL.md — with instructions for saving and searching memories. The idea: type /fragrag and Claude knows what to do.
It didn't work. Two problems:
1. Missing YAML frontmatter. OMC's learner system requires specific fields (id, name, triggers, source) to register a skill. Without them, the skill was silently skipped — completely invisible to OMC's trigger system.
2. OMC learned skills aren't slash commands. Even with correct frontmatter, learned skills (in ~/.claude/skills/omc-learned/) are only discovered by OMC's hook-based trigger system for auto-injection. The builtin skill loader — which registers /slash-commands — only reads from the OMC plugin's own bundled skills/ directory. This is a fundamental architecture gap in OMC.
Phase 3: Native Claude Command
The fix: move fragRag out of OMC's skill system entirely and into Claude Code's native command system. A .md file in ~/.claude/commands/ becomes a /slash-command directly — no OMC involvement needed.
~/.claude/commands/fragrag.md → /fragrag
This worked immediately. /fragrag became available as a native slash command that instructs Claude how to interact with the memory server.
Phase 4: Skills Sync via Symlink
The OMC skill discovery exposed another problem: skills were being copied from the Git repo into ~/.claude/skills/omc-learned/ by the install script. This meant:
- Skills drifted out of sync between the repo and the installed copies
- New skills required re-running
install.shon every machine - There was no single source of truth
The fix: replace the copy with a symlink.
~/.claude/skills/omc-learned → ~/claude-config/skills/
Now Git is the single source of truth. git pull is all you need — OMC reads skills directly from the repo through the symlink.
Phase 5: The Auto-Search Problem
With /fragrag working, the next goal was making Claude automatically search fragRag at the start of every session — so you'd never have to manually orient it.
Attempt 1: CLAUDE.md directive. A CRITICAL instruction was added to ~/.claude/CLAUDE.md telling Claude to search fragRag on the first message of every session. Result: Claude read the instruction, acknowledged it when asked, but didn't follow it. The directive was buried at the bottom of a long file after all the OMC configuration, and Claude simply didn't prioritize it.
Attempt 2: /start with broad searches. A slash command that ran multiple fragRag searches on startup to preload context. This worked but was wasteful — it pulled memories you might never need and slowed down every session start.
Attempt 3: /start as a session rule. The winning approach. Instead of searching fragRag upfront, /start simply establishes a rule for the session: fragRag is the system of record — search it before saying "I don't know." No upfront queries, no wasted tokens. Claude just knows where to look when it needs to.
The /start command also:
- Checks the
claude-cli-configGit repo for updates and runsinstall.shif needed - Checks git status of the working directory
- Presents a brief oriented summary and asks "What are we working on?"
This works reliably because the user explicitly invokes it — no hoping Claude follows buried instructions — and it's fast because it doesn't preload data it might not need.
Phase 6: Config as Code
Everything is now in a single Git repo (gitDiot-Org/claude-cli-config):
claude-cli-config/
├─ commands/ # Native Claude slash commands
│ ├─ start.md # Session bootstrap (/start)
│ └─ fragrag.md # Memory operations (/fragrag)
├─ skills/ # OMC learned skills (symlinked)
├─ memory/ # File-based memory templates
├─ settings/ # Platform-specific settings.json
│ ├─ settings-wsl.json
│ ├─ settings-linux.json
│ ├─ settings-windows.json
│ └─ claude-md-append.md
├─ articles/ # Documentation like this
├─ install.sh # Sync config to ~/.claude/
└─ setup.sh # Full new-machine setup
install.sh handles everything: symlinks skills, copies commands, installs memories, applies settings, appends CLAUDE.md directives (with idempotent markers so re-runs don't duplicate).
What We Learned
OMC skills vs. Claude commands are different systems. OMC's learned skills are for hook-based auto-injection via trigger keywords. Claude's native commands (in ~/.claude/commands/) are for /slash-command invocation. If you want a reliable slash command, use the native system.
Passive instructions don't reliably trigger actions. Putting "always do X on first message" in CLAUDE.md doesn't guarantee Claude will do it. An explicit /start command that the user invokes is far more reliable than hoping Claude follows a buried directive.
Set rules, don't preload data. The first instinct was to search fragRag broadly at startup to preload context. But that's slow and wasteful — most memories pulled won't be relevant. The better pattern: establish the rule that fragRag is the system of record, and let Claude search on demand when it actually needs information. Lazy loading beats eager loading.
Symlinks beat copies for config sync. Any time you're copying files from a repo to an install location, consider whether a symlink would eliminate the sync problem entirely.
Config-as-code scales. Once skills, commands, settings, and directives all live in a Git repo with an install script, adding a new machine is: clone, run script, type /start. The whole team stays in sync through normal Git workflows.
The End State
Starting a new Claude session on any machine:
- Open Claude Code
- Type
/start - Claude syncs the config repo, checks git status, and establishes fragRag as the memory system
- Ask any question — if Claude doesn't have the answer locally, it searches fragRag automatically
The "kids" test: ask "what do my kids say?" in a brand new session after /start. Claude searches fragRag, finds the memory, and answers — even though it's never seen that information in this session's context. No manual setup, no context loss, no drift between machines.
Related: Building a Persistent RAG Memory System for Claude Code — the technical architecture reference.