Resolve folder case on write so notes don't split into case-only twin folders · Issue #1796 · basicmachines-co/basic-memory · GitHub
Skip to content

Resolve folder case on write so notes don't split into case-only twin folders #1796

Open

Description

@phernandez

Problem

A project can end up with two folders that differ only by letter case, for example marketing/Teams and marketing/teams, or customers/CPC and customers/cpc. Both production cases behind #1787 look like this. The likely source is agents writing notes with inconsistent casing. In Cloud's storage (Tigris keys) and on Linux, the two spellings are separate folders, so nothing stops the split.

Problems this causes:

  • Wiki: the projector cannot project either folder. fix(core): report case-only Wiki scope collisions instead of failing the run #1789 skips both and reports the collision instead of failing the run, so neither folder gets an index.md until the user renames one.
  • Sync: macOS and Windows file systems are case-insensitive by default, and macOS also normalizes Unicode. A workspace synced there through rclone or WebDAV merges the two folders on disk. Notes with the same filename in both folders overwrite each other.
  • Browsing: the user sees two folders for one topic, and notes are split between them.

#1789 handles the symptom. This issue is about preventing the split.

Proposed fix

When a write targets a folder path that matches an existing folder under the portable-path key (casefold plus Unicode NFC, the same _portable_path_key the wiki projector uses), write into the existing folder's spelling instead of creating a new one.

  • Apply this on every write path that creates folders: write_note, move_note, and API entity create and update. The rule should live in one place, not be copied per tool.
  • Resolve each path segment against the folders that already exist, so marketing/teams/q4 lands in marketing/Teams/q4.
  • When a path is rewritten, return the actual path in the tool response, so an agent learns the real spelling.
  • Leave existing duplicates alone. Merging folders that already exist is a separate decision, because it moves user files.

First step

Confirm where the production duplicates came from. Check the note history or write activity for the notes under marketing/teams and customers/cpc in the two affected workspaces (cloud Logfire issue #2636). If they came from local sync or import rather than MCP writes, the fix also needs to cover the sync path.

Acceptance

  • Writing marketing/teams/new-note when marketing/Teams/ exists creates marketing/Teams/new-note.md and reports that path.
  • A path differing only by Unicode normalization resolves the same way.
  • A folder that is genuinely new is created as written.
  • Tests cover write, move and API create, on both SQLite and Postgres.

Related: #1787, #1789.

Activity

  1. added
    cost-review-2026-10October 2026 COGS review: cost leaks, heavy tenants, and production error triage
    on Oct 20, 2026
  2. claude commented on Oct 20, 2026

    @claude
    Contributor

    Claude finished @phernandez's task in 20s —— View job


    Triage

    Notes for whoever picks this up

    • Do the "First step" before implementing. If the duplicates came from local sync or import rather than MCP writes, the fix has to cover the sync path as well.
    • The resolver reads the existing folder set. Per the consistency model in CLAUDE.md, don't add SELECT ... FOR UPDATE or wider transactions for this. A concurrent write that creates a twin is derived-state drift, not a canonical-content problem.
    • Return the rewritten path in the tool response so agents learn the real spelling.

    I haven't made any code changes. This pass was triage only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    cloudBasic Memory Cloudcost-review-2026-10October 2026 COGS review: cost leaks, heavy tenants, and production error triageenhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions