Skip to content
skhynixPublic

About

Procedural Memory layer for AI agents

Resources

Stars

10 stars

Watchers

1 watching

Forks

Repository files navigation

MemFlow

MemFlow retrieves relevant stored skills for a task in Claude Code. Its plugin injects a short catalog of matches, then Claude reads a selected SKILL.md by exact ID through MCP. Registration stores the entire skill root in Qdrant. Each read restores the latest file set into a new local directory, while returning only the Markdown and small metadata fields. Stored skills retain their trust state.

Install the Claude Code plugin

Install uv 0.12.24 and use Claude Code 2.1.220 or later. You need an existing Qdrant service and an OpenAI-compatible embedding endpoint. MemFlow does not provision these services. The plugin prepares its own managed Python 3.12 and dependencies; users do not clone MemFlow, install a Python package, or create a project .env.

Enter these commands in the Claude Code prompt:

/plugin marketplace add skhynix/MemFlow
/plugin install memflow@memflow-plugins

Select user scope and complete Claude's plugin configuration form. Connection settings are shared across your projects.

Configuration field Value
Use system certificates during installation Defaults to off. Enable for runtime downloads through a corporate CA trusted by the operating system
Qdrant URL Existing HTTP(S) service endpoint
Collection Defaults to memflow_skills
Qdrant API key Optional; leave empty for unauthenticated access
Embedding API base URL OpenAI-compatible base URL; MemFlow appends /embeddings
Embedding model Model identifier served by your endpoint
Embedding dimensions Positive integer output dimension
Embedding API key Optional; leave empty to omit the Authorization header

URLs cannot embed credentials or query strings. Use /plugin configure to select MemFlow and edit these settings. Credentials stay in Claude-managed configuration and process memory. The plugin does not read .env or inherit SDK connection, hybrid, or reranker tuning variables. No /memflow:setup command is required.

Start a fresh Claude session after installation. Both the startup hook and MCP launcher ensure the runtime is ready before using it, with an installation lock and a 600-second preparation deadline. MCP connects automatically when preparation and server initialization finish within Claude's startup window (30 seconds by default). A longer first download can exceed that window while the startup hook continues preparation. Once /memflow:status reports Runtime ready, reconnect MemFlow in /mcp. Claude can cache a failed connection across restarts, so restarting alone may not reconnect it. Runtime ready and MCP connected are separate states.

If your network uses a corporate certificate authority already trusted by the operating system, enable Use system certificates during installation in MemFlow's /plugin configure form. Then start a fresh session with the ordinary claude command. The saved choice covers Python downloads and dependency installation during first setup, updates that need a new runtime, and explicit /memflow:status --repair. A prepared runtime needs no download settings.

The option defaults to off, retaining uv's bundled certificate roots. When on, certificate verification remains enabled and uses the operating system's trust store. Shell UV_* settings do not override the saved choice. In WSL, the CA must be trusted inside Linux. This setting does not install a CA, configure proxy credentials, or change TLS for the Qdrant and embedding clients. See uv certificate configuration.

The plugin targets Linux x86_64/arm64 (including Linux inside WSL) and macOS arm64 (Apple Silicon). Intel macOS and native Windows are unsupported. Installation CI targets Ubuntu x86_64; Linux arm64 and macOS arm64 require separate native installation checks before release.

Manage stored skills

Enter these commands in Claude's prompt, with paths relative to your session's project directory:

/memflow:status
/memflow:add ./skills/review --trust-state trusted
/memflow:list
/memflow:sync ./skills/review

add accepts a skill directory or a SKILL.md file. It preserves the library's source-derived ID and defaults to untrusted data unless you explicitly select a trust state. Only mark instructions you trust as trusted. add may create the collection and required payload indexes after checking service compatibility.

sync accepts an existing exact ID or source path. It retains the stored user, source, and trust state, marks missing sources stale, and never initializes a collection or indexes. list accepts --user-id and --trust-state filters; add also accepts --user-id. Registration stores a snapshot: editing a source file requires an explicit sync.

Hooks and MCP use the project selected when the Claude session starts. Adding access with /add-dir or changing the working directory during a session does not retarget MemFlow's relative paths, logs, or project configuration. Start a new Claude session in another project to use it as the MemFlow project.

Ordinary task prompts automatically retrieve relevant skills. Management skills load only when invoked, and management writes require an explicit current user request, including a direct natural-language request. This is a workflow under Claude's normal tool permissions: the plugin adds no permission rules or approval bypass, and skill frontmatter does not make MCP tools technically uncallable.

Installing or configuring MemFlow keeps native Claude skills visible. Disabling the plugin through /plugin stops its integrations; Qdrant records remain.

Diagnose and repair

/memflow:status
/memflow:status --repair

Plain status is read-only. It runs an independent shell diagnostic even before Python or MCP is available. When MCP is connected, it also validates settings, reads Qdrant collection metadata, and requests an embedding for a fixed diagnostic string. Without MCP, service health is unknown. No status operation creates a collection, builds indexes, imports skills, or changes Claude settings.

Repair explicitly retries runtime preparation. It never changes connection settings or stored skills. A missing collection is a valid pre-import state.

Preparation failures report the failing stage and a process exit code or OS error number when available. Run explicit repair to reproduce an installation failure and see its diagnostic. Dependency installation and import validation output is withheld because it can contain URLs or credentials.

Result Action
Missing or wrong uv Install uv 0.12.24 and run explicit repair
Missing configuration Select MemFlow in /plugin configure
Runtime preparation still running Wait for automatic preparation to finish
Runtime preparation failed or interrupted Run explicit repair; reconnect in /mcp afterward
Runtime ready, MCP disconnected Reconnect in /mcp; repair is unnecessary
Published runtime damaged or lifecycle unknown Close affected sessions, then uninstall/reinstall to recreate plugin data
Authentication failure or timeout Check the indicated service and Claude-managed credentials
Missing collection Import a skill with an explicit add
Incompatible dense schema Select a compatible collection with the configured dimension
Read-only sparse schema Read existing dense vectors, or choose a separate dense-only collection for add/sync
No retrieval result Check list/status, then retrieval thresholds and the metadata-only hook log

The plugin uses dense retrieval and supports unnamed dense vectors or a named dense vector, including dense reads from collections that also have sparse vectors. Writes require a dense-only cosine collection with the configured vector size. Embeddings longer than that size use the library's truncation and L2-normalization rule; short, invalid, or zero vectors fail. Import and sync never report success with a fallback hash or zero embedding. Embedding status reports the original source_dimensions, effective dimensions, and dimension_reduction_applied from the same diagnostic request. Check these fields when choosing a smaller vector size; reduction must be appropriate for the embedding model.

Restart affected Claude sessions after changing endpoints, collections, models, or dimensions. A different model requires a fresh compatible collection and explicit re-import, even if its vector length is unchanged. MemFlow never silently re-embeds records, resizes a collection, or migrates a sparse schema.

Project retrieval and session state

Optional .memflow/claude-hook.json settings control retrieval and session behavior. Defaults work without creating this file. Endpoints, credentials, and installer fields are not plugin project settings.

{
  "retrieval": {"top_k": 3, "min_score": 0.2, "timeout_ms": 2000},
  "claude": {
    "reread_after_compaction": true,
    "session_dedupe": {"rollout": "off"}
  }
}

Relative log and state paths resolve from the session project, never the plugin cache. The default hook log is .memflow/logs/skill_context_hook.jsonl; session records are under .memflow/claude-sessions. They contain metadata, not raw prompts, skill bodies, tool responses, transcripts, or service credentials. Retrieval and state failures leave Claude usable with a sanitized diagnostic.

After compaction, MemFlow resets activation state and asks Claude to reread previously successful exact IDs. The reminder prioritizes recent reads within 8,000 UTF-16 units and explains instruction versus untrusted-data handling. Only recognized successful calls to mcp__plugin_memflow_memflow__read_skill update read history. Failed or malformed calls do not count as successful reads; a failed read invalidates that ID's current disclosure without deleting historical successful-read metadata.

/clear and startup start with empty session history. Resume and ordinary session end preserve it. Reread tracking defaults to on; experimental catalog deduplication still defaults to off. Setting reread_after_compaction to false disables new read tracking. Both features must be off to disable session-state access. A reminder requests current stored content; it does not prove Claude reread it.

Optional native catalog control

Catalog status is read-only by default. Mutations require an explicit mode and scope:

/memflow:catalog
/memflow:catalog minimize --scope repository
/memflow:catalog disable --scope repository
/memflow:catalog restore --scope repository

For a non-Git project use --scope directory. In Git repositories, local settings are shared through <main-checkout>/.claude/settings.local.json. Restrictions therefore affect the main checkout and linked worktrees. Discovery uses native skills in the current checkout and Claude's effective configuration directory, including CLAUDE_CONFIG_DIR. Name-based overrides can affect matching skills in other worktrees. Plugin skills and dynamically loaded skills are not exhaustively covered by native discovery.

Git must be on Claude's PATH even for directory scope: MemFlow checks whether the directory belongs to a repository before choosing the settings target. Git 2.34 is supported. Older Git's line-delimited worktree output is checked against repository metadata before choosing the settings root; ambiguous paths are refused. Git 2.36 or newer supports paths containing line breaks. If Git reports dubious ownership, verify the checkout owner and trust before configuring safe.directory for that checkout. MemFlow does not change Git trust settings or fall back to directory scope when repository verification fails.

Minimize makes discovered native skills user-invocable only; disable turns them off. Both request bundled skills to be disabled. Existing per-skill user overrides and user-edited owned values are preserved and reported as conflicts. Unsupported Git layouts, missing main checkouts, home-root repositories, ownership exceptions, symlinked state/settings paths, invalid settings, and wrong scopes refuse writes.

Restore undoes only unchanged MemFlow-owned keys, using each key's original presence and value. If a key is already back at its original presence/value and has no unresolved pending operation, restore releases its ownership record without rewriting the setting. Other user changes remain conflicts. It does not force all skills visible. The journal at <effective-settings-root>/.memflow/claude-catalog-state.json survives plugin removal. Restore before uninstall, or reinstall and restore afterward. Uninstall does not restore native catalog settings.

For manual recovery, inspect the journal's canonical target, then compare each owned key's committed presence/value with the current setting. Revert only unchanged entries to baseline, deleting the key if its baseline was absent. bundled means disableBundledSkills; skill:<name> means that one entry under skillOverrides. A pending entry records before, after, and baseline: matching before is unapplied, matching after is applied, and any other value is an external conflict to preserve. Keep unresolved evidence and the journal until recovery is complete. Never replace a whole settings file from an old snapshot. Malformed, missing, unsupported-version, or wrong-target journals cannot establish ownership and require manual investigation.

MemFlow writers share an OS lock and recover pending writes per key. A byte comparison detects many external edits before atomic replacement. It cannot eliminate the final check/replace race with other programs or identify an external edit that writes exactly the same value.

Python library and benchmarks

Python consumers install this repository as a package, for example with uv sync --locked --dev in a development checkout. This is separate from plugin installation. There are no public memflow or memflow-mcp terminal entry points.

from memflow import MemFlow, SkillRecord

memory = MemFlow()  # Qdrant configuration from the environment and CWD .env
record = SkillRecord(title="Release checks", content="Check tests and release notes.")
memory.add(record)
hits = memory.search("prepare a release", user_id="default")
stored = memory.get_skill(record.id)
memory.delete(record.id)

The Python library retains environment-based configuration and optional hybrid search. .env.example is for SDK and benchmark use only. Explicit constructor arguments override the environment. MemFlow(store=store, use_env=False) uses an injected store; hybrid_search=False selects dense retrieval and rerank=False disables reranking independently. The plugin selects both policies and ignores inherited hybrid and reranker configuration. QdrantStore(provision=False) reads schemas without creating collections or indexes; ordinary Python construction retains provisioning by default. Explicit strict_embedding=True rejects fallback embeddings without changing the default SDK policy.

add accepts one SkillRecord or a list, and async operations remain available. Records and searches use kind="skill". File indexing uses add_skill(path) and sync_skill(path_or_id). The library's get_skill accepts an ID, title, or name; plugin read_skill requires an exact ID. The plugin's stricter existing-record sync and dense-only write policy do not remove optional SDK capabilities.

Optional SDK reranking

Set MEMFLOW_RERANKER_PIPELINE in your SDK environment to ce, llm, ce_llm, or llm_ce to rerank candidates after dense or hybrid retrieval. The default is none. See .env.example for endpoints, candidate depths, stage caps, and timeouts.

For an LLM stage, install the matching provider extra with uv sync --extra openai or uv sync --extra ollama. The CE stage uses the core HTTP client and needs no additional provider extra. Configure RERANKER_LLM_PROVIDER, RERANKER_LLM_MODEL, RERANKER_LLM_API_BASE, and RERANKER_LLM_API_KEY; these retain LLM_* fallbacks. Clients are created only when reranking runs. Invalid stage configuration or endpoint failures warn and fall back to retrieval order.

Single-string searches, including search_async, use the configured pipeline. List-query batches bypass hybrid retrieval and reranking. search(..., rerank=False) bypasses reranking for one call. For SkillRet, the default async runner measures the configured pipeline; --sync uses dense batches and --mode dense sparse hybrid explicitly measures retrieval without reranking.

Optional MemMachine memory queries

MemMachine is a separate source for existing episodic and semantic memory. Install its optional SDK with uv sync --extra memmachine and call the query module explicitly:

from memflow.memmachine_memory import MemMachineMemoryClient

client = MemMachineMemoryClient(
    base_url="http://localhost:8080", org_id="default", project_id="memflow"
)
try:
    response = client.search(
        "What are my release preferences?",
        user_id="alice",
        set_metadata={"user_id": "alice"},
    )
finally:
    client.close()

The project must already exist. Episodic memory uses the supplied user_id metadata filter; set_metadata must match the server's existing semantic set configuration for that user. The example mapping is valid only for a server configured that way. The SDK response retains both memory types without conversion to skill records. This module does not create projects, write or delete memory, or participate in skill search, hooks, MCP, or benchmarks.

MemMachineMemoryClient.from_env() reads the optional MEMMACHINE_* process settings in .env.example. It does not load an env file. Import, construction, and from_env() do not load the SDK or connect; the first valid search does. Close the client when finished; a closed client cannot search.

Benchmarks

The benchmark harnesses evaluate skill retrieval with SkillRet and SkillReason-Bench. Install optional plotting dependencies with uv sync --extra benchmark.

The SkillRet benchmark is installed directly from HuggingFace (requires git-lfs):

git lfs install
uv run benchmark/install_benchmark.py skill_ret_bench
uv run benchmark/install_benchmark.py skill_ret_bench --commit-hash-skillret <hash>

SkillReason-Bench has a separate downloader and supports official metrics, predictions, and Recall@k plots from saved results:

uv run benchmark/skill_reason_bench/download_data.py
uv run --extra benchmark benchmark/skill_reason_bench/plot_recall_curves.py \
  --results results/skillreason.json --by-domain

See the SkillReason-Bench guide for seeding, retrieval, evaluation, and plotting options.

Skill file limits

File-based registration captures the entire skill root, including arbitrary nested files, hidden files, binary data, executable flags and empty directories. It excludes .git entries at every depth, but includes .gitignore and ignored files. Symlinks and special files fail the entire registration. Paths must be canonical UTF-8 relative paths; filenames containing backslashes or non-UTF-8 bytes are rejected, including on filesystems that permit them.

The standalone build_resource_manifest(root_path) helper retains its existing scripts/references/assets discovery behavior without registration limits. File-based registration captures the full root and derives its resource metadata from that bundle without reading the files again.

The defaults are 10 MiB of original bytes and 1,000 regular files, including SKILL.md. These are MemFlow operational limits, not Agent Skills restrictions. Set Python environment variables MEMFLOW_SKILL_MAX_BYTES and MEMFLOW_SKILL_MAX_FILES, or pass BundleLimits(max_bytes=..., max_files=...) to load_skill(..., limits=...) or MemFlow(..., bundle_limits=...). In Claude's /plugin configure memflow, use skill_max_bytes and skill_max_files. Values must be positive integers. Directory count and depth have no separate budget. These file limits therefore do not bound traversal work for trees containing many empty directories.

QDRANT_MAX_REQUEST_BYTES (Python) or qdrant_max_request_bytes (plugin) sets a separate serialized request budget, defaulting to 32 MiB. Match it to the Qdrant deployment: Base64, JSON, vectors and metadata add overhead beyond source bytes. Passing a client budget check does not guarantee server acceptance.

Each complete file bundle is stored in the same Qdrant point as its instructions. Dense and hybrid search and list operations explicitly omit bundle bytes; search text and reranker input still use only the existing body and metadata. Projected records have bundle_loaded=False and cannot be used in replacement writes. Use store.get(id) to fetch a complete record before changing and saving it. Writes wait for Qdrant to confirm completion. A timeout is an error with an unknown remote outcome; MemFlow does not retry a reduced file set. Single and batch writes propagate failures. A failed batch can have applied some records; it does not roll them back. Async batches wait for all submitted writes before reporting a failure.

sync_skill compares the full bundle digest, so resource additions, edits, deletions, executable flag changes and empty directory changes trigger updates without requiring a Markdown edit. An unchanged bundle skips the write. A missing source is marked stale while its stored files remain available; collection failures leave the stored set intact. Stale marking patches only the stale flag and governance warnings, leaving concurrent bundle, content, vector, and unrelated metadata changes intact. These field updates do not provide a transaction or an atomic warning append. Custom BaseStore backends must implement mark_skill_stale(id, warnings) as a metadata-only update to support missing-source sync. The default raises NotImplementedError; it never replaces a point with a previously read snapshot.

Using downloaded skill files

read_skill(skill_id) returns id, name, trust_mode, content, skill_root (an absolute local directory) and bundle_digest. Resolve relative references against skill_root, not the original registration path. For a skill that contains scripts/run.sh and relative dependencies, the host can run:

cd /path/from/skill_root
./scripts/run.sh /absolute/project/output

The agent and host decide whether to execute anything. MemFlow neither executes commands nor changes the process working directory. Save outputs to the project if they must outlive the download. This path contract targets local stdio MCP.

Every call fetches and validates the full latest set and creates a new directory, even for an unchanged skill. Earlier directories remain unchanged by sync and later reads, and survive /clear while the MCP process lives. Shutdown attempts to delete them; forced termination or cleanup failures can leave temporary files. There is no aggregate download budget or early eviction during the process lifetime; repeated reads increase temporary disk usage. Invalid paths, Base64, sizes, hashes, mismatched Markdown or failed writes fail the read, and partial directories are cleaned up. Old stored records without a bundle are not supported by read_skill; re-register from the source explicitly.

About

Procedural Memory layer for AI agents

Resources

Stars

10 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages