You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
With namespace.enable_auto_ns=true and no explicit namespace.rules, all files indexed from a memory_dir whose basename is memory / memories / plans silently land in default namespace — even when the user clearly intended the parent folder name (e.g., the Claude project id) to be the namespace.
Observed on a post-v0.1.12 install with auto-discovered Claude project memory dirs: 766 indexed chunks across 29 ~/.claude/projects/*/memory paths, all with namespace='default'.
Repro
mm init (or rely on the auto_discover migration) so config.indexing.memory_dirs contains entries like ~/.claude/projects/FOO/memory.
In config.json: "namespace": {"enable_auto_ns": true} (no rules, no custom default_namespace).
mm index ~/.claude/projects/FOO/memory (or reindex via web UI).
sqlite3 ~/.memtomem/memtomem.db "SELECT namespace, COUNT(*) FROM chunks GROUP BY namespace"
→ every row is default.
Expected: something like FOO (the Claude project id) for every file in that dir, since that's the only identifier the user actually cares about.
The guard is intentional: without it, parent.name would be literally "memory" for every Claude-projects file, which is useless as a namespace. But the guard only suppresses the bad option — it doesn't derive the good one. Falls through to default_namespace == "default" → returns None → ChunkMetadata.namespace default ("default") kicks in.
For a memory_dir path like ~/.claude/projects/FOO/memory, the useful namespace lives at memory_dir_path.parent.name (i.e., FOO), not at file_path.parent.name. The current logic has no way to express that.
Scope
Applies to any memory_dir whose basename is non-discriminating (memory, memories, plans, notes, …) — exactly the shape produced by the auto-discovered provider dirs shipped since v0.1.12:
~/.claude/plans (claude-plans category, single dir so less acute)
~/.codex/memories (codex category, single dir so less acute)
The user's realistic workaround is hand-crafting a namespace.rules entry per project, which defeats the "auto" part of enable_auto_ns.
Proposed directions
Not ordering these — each has tradeoffs:
Extend _resolve_namespace fallback: when the parent-of-file hits memory_roots, fall through to memory_dir_path.parent.name. Gated on a whitelist of "container" basenames (memory / memories / plans) so ordinary memory_dirs aren't surprised. Zero user-config change; implicit behavior shift may surprise existing installs though.
New placeholder for NamespacePolicyRule.namespace: something like {ancestor:N} to pick N levels up. User writes:
Explicit + no behavior shift for existing installs, but requires docs + wizard hand-holding.
Ship a preset policy bundle with the mm init provider-dirs step: when the wizard picks Claude-memory dirs, it also appends a matching NamespacePolicyRule (e.g., claude:{parent} with a placeholder that means "project id"). Keeps the wizard as the single source of truth for provider integration.
My instinct is (2) + (3) together — (2) gives the primitive, (3) applies it automatically for the known provider surface, and (1) is left on the table to avoid implicit behavior drift for non-provider memory_dirs that legitimately expect the current guard.
Evidence it's not triggered by the current PR
The DB in question was populated by the pre-existing POST /api/index + mem_index paths, both of which go through _resolve_namespace unchanged since before v0.1.12. Not introduced by #295 (editable widget + per-dir status).
Summary
With
namespace.enable_auto_ns=trueand no explicitnamespace.rules, all files indexed from amemory_dirwhose basename ismemory/memories/planssilently land indefaultnamespace — even when the user clearly intended the parent folder name (e.g., the Claude project id) to be the namespace.Observed on a post-v0.1.12 install with auto-discovered Claude project memory dirs: 766 indexed chunks across 29
~/.claude/projects/*/memorypaths, all withnamespace='default'.Repro
mm init(or rely on theauto_discovermigration) soconfig.indexing.memory_dirscontains entries like~/.claude/projects/FOO/memory.config.json:"namespace": {"enable_auto_ns": true}(norules, no customdefault_namespace).mm index ~/.claude/projects/FOO/memory(or reindex via web UI).sqlite3 ~/.memtomem/memtomem.db "SELECT namespace, COUNT(*) FROM chunks GROUP BY namespace"→ every row is
default.Expected: something like
FOO(the Claude project id) for every file in that dir, since that's the only identifier the user actually cares about.Root cause
packages/memtomem/src/memtomem/indexing/engine.py:_resolve_namespace(L291-326):The guard is intentional: without it,
parent.namewould be literally"memory"for every Claude-projects file, which is useless as a namespace. But the guard only suppresses the bad option — it doesn't derive the good one. Falls through todefault_namespace == "default"→ returnsNone→ChunkMetadata.namespacedefault ("default") kicks in.For a
memory_dirpath like~/.claude/projects/FOO/memory, the useful namespace lives atmemory_dir_path.parent.name(i.e.,FOO), not atfile_path.parent.name. The current logic has no way to express that.Scope
Applies to any
memory_dirwhose basename is non-discriminating (memory,memories,plans,notes, …) — exactly the shape produced by the auto-discovered provider dirs shipped since v0.1.12:~/.claude/projects/*/memory(claude-memory category)~/.claude/plans(claude-plans category, single dir so less acute)~/.codex/memories(codex category, single dir so less acute)The user's realistic workaround is hand-crafting a
namespace.rulesentry per project, which defeats the "auto" part ofenable_auto_ns.Proposed directions
Not ordering these — each has tradeoffs:
_resolve_namespacefallback: when the parent-of-file hitsmemory_roots, fall through tomemory_dir_path.parent.name. Gated on a whitelist of "container" basenames (memory/memories/plans) so ordinarymemory_dirsaren't surprised. Zero user-config change; implicit behavior shift may surprise existing installs though.NamespacePolicyRule.namespace: something like{ancestor:N}to pick N levels up. User writes:{ "rules": [ { "path_glob": "**/.claude/projects/*/memory/**", "namespace": "claude:{ancestor:2}" } ] }mm initprovider-dirs step: when the wizard picks Claude-memory dirs, it also appends a matchingNamespacePolicyRule(e.g.,claude:{parent}with a placeholder that means "project id"). Keeps the wizard as the single source of truth for provider integration.My instinct is (2) + (3) together — (2) gives the primitive, (3) applies it automatically for the known provider surface, and (1) is left on the table to avoid implicit behavior drift for non-provider
memory_dirsthat legitimately expect the current guard.Evidence it's not triggered by the current PR
The DB in question was populated by the pre-existing
POST /api/index+mem_indexpaths, both of which go through_resolve_namespaceunchanged since before v0.1.12. Not introduced by #295 (editable widget + per-dir status).Related
NamespacePolicyRuleonly supports{parent}(immediate parent) — seepackages/memtomem/src/memtomem/config.py:_ALLOWED_NS_PLACEHOLDERS.