Neuroloom

Cookbooks

CLAUDE.md Migration

A 300-line CLAUDE.md loads into every session whether or not it's relevant. Migrate the knowledge sections into Neuroloom and inject only what each session needs — shrinking context overhead while improving relevance.

Problem

CLAUDE.md starts as a short conventions file and grows into a documentation dumping ground. Database patterns, architecture decisions, API conventions, historical context, runbook fragments — it all accumulates. By the time the file hits 300 lines, Claude Code loads 20,000+ tokens of context every session, most of it irrelevant to the current task. Trim it, and the relevant knowledge disappears too.

Persona

Kenji maintains a FastAPI monorepo with a 340-line CLAUDE.md. The file contains coding standards, architecture decisions, environment setup instructions, historical context about migrations, and notes about external API quirks. Every session loads all of it. He wants Claude Code to know what it needs to know for each session — without loading everything every time.

Prerequisites

  • Neuroloom plugin installed and configured (see Quickstart)
  • CLAUDE.md file at least 100 lines (shorter files don't benefit from migration)
  • Environment variables:
    export MEMORIES_API_TOKEN="nl_your_api_key_here"
    export MEMORIES_WORKSPACE_ID="ws_your_workspace_id_here"

Step 1: Audit CLAUDE.md — map categories to memory types

Read through CLAUDE.md and categorize each section. This determines which memory type to use for each entry.

Typical mapping for a monorepo CLAUDE.md:

Section typeMemory typeExample
Architecture decisionsdecision"Why we use StrEnum over Postgres ENUM"
Coding patternspattern"Always use selectinload() for relationship loading"
Conventionsconvention"Every DB query must filter by workspace_id"
Dependency quirksdecision + dependency tag"httpx 0.27.x doesn't retry on 429 by default"
Environment setupgeneral + configuration tag"Dev environment requires Docker Compose v2"
Bug fixes / gotchasincident"pgvector rollback doesn't undo HNSW index — use DELETE"
Historical contextarchitecture"We moved from sync to async SQLAlchemy in D7"
Learning / external APIdiscovery"Railway adds a trailing slash that strips auth headers on redirect"

Create a migration inventory before writing any code. Mark each section with its target memory type and estimated importance:

[ ] Technology Stack section → architecture (importance: 0.7)
[ ] API Case Transformation → pattern (importance: 0.9)
[ ] pgvector Conventions → convention (importance: 0.95)
[ ] ARQ Job Conventions → pattern (importance: 0.88)
[ ] Coding Standards: Python → convention (importance: 0.85)
[ ] Coding Standards: TypeScript → convention (importance: 0.80)
[ ] Trailing slash redirect bug → incident (importance: 0.92)

Step 2: Store each category as typed memories

Migrate one category at a time. Start with the highest-importance sections — the ones that cause mistakes when unknown.

Use memory_store:
- title: "pgvector HNSW non-transactional behaviour"
- memory_type: "incident"
- content: "pgvector's HNSW index is non-transactional. Rolling back a transaction does NOT undo index updates. If a test inserts a vector and the transaction rolls back, the vector remains in the HNSW index even though it's gone from the table. Always use DELETE or TRUNCATE for test cleanup — not transaction rollback. This affects any code that runs tests against a shared pgvector index."
- concepts: ["pgvector", "HNSW", "transactions", "testing", "rollback"]
- files: ["api/neuroloom_api/"]
- importance: 0.95
- tags: ["gotcha", "testing", "pgvector"]
Use memory_store:
- title: "SQLAlchemy workspace isolation requirement"
- memory_type: "convention"
- content: "Every database query must filter by workspace_id. No exceptions. This is a security invariant — not a performance optimization. pgvector cosine similarity queries do not enforce tenant isolation through the index; the WHERE workspace_id = :workspace_id clause is the only thing preventing cross-tenant data access. Any new query or endpoint that omits workspace_id is a security bug."
- concepts: ["workspace isolation", "multi-tenancy", "security", "SQLAlchemy", "pgvector"]
- files: ["api/neuroloom_api/"]
- importance: 1.0
- tags: ["security", "invariant"]
Use memory_store:
- title: "ARQ job serialization constraint"
- memory_type: "pattern"
- content: "ARQ background jobs must receive only JSON-serializable arguments. Never pass SQLAlchemy ORM objects to job functions — pass IDs as strings and reload from DB inside the job. The ARQ worker runs in a separate process with its own database connection pool and cannot deserialize ORM model instances from another process."
- concepts: ["ARQ", "background jobs", "serialization", "async"]
- files: ["api/neuroloom_api/workers/"]
- importance: 0.88
- tags: ["pattern", "arq"]
import os
import httpx

token = os.environ["MEMORIES_API_TOKEN"]
workspace_id = os.environ["MEMORIES_WORKSPACE_ID"]

# Memories to migrate from CLAUDE.md
migrations = [
    {
        "title": "pgvector HNSW non-transactional behaviour",
        "memory_type": "incident",
        "narrative": (
            "pgvector's HNSW index is non-transactional. Rolling back a transaction "
            "does NOT undo index updates. Always use DELETE or TRUNCATE for test cleanup — "
            "not transaction rollback. This affects all code that runs tests against a "
            "shared pgvector index."
        ),
        "concepts": ["pgvector", "HNSW", "transactions", "testing"],
        "source_files": ["api/neuroloom_api/"],
        "importance_score": 0.95,
        "tags": ["gotcha", "testing", "pgvector"],
    },
    {
        "title": "SQLAlchemy workspace isolation requirement",
        "memory_type": "convention",
        "narrative": (
            "Every database query must filter by workspace_id. No exceptions. "
            "pgvector similarity queries do not enforce tenant isolation through the index — "
            "the WHERE workspace_id = :workspace_id clause is the only guard against "
            "cross-tenant data access. Any query that omits workspace_id is a security bug."
        ),
        "concepts": ["workspace isolation", "multi-tenancy", "security", "SQLAlchemy"],
        "source_files": ["api/neuroloom_api/"],
        "importance_score": 1.0,
        "tags": ["security", "invariant"],
    },
    {
        "title": "ARQ job serialization constraint",
        "memory_type": "pattern",
        "narrative": (
            "ARQ background jobs must receive only JSON-serializable arguments. "
            "Never pass SQLAlchemy ORM objects to job functions — pass IDs as strings "
            "and reload from DB inside the job. The ARQ worker runs in a separate process "
            "with its own connection pool."
        ),
        "concepts": ["ARQ", "background jobs", "serialization", "async"],
        "source_files": ["api/neuroloom_api/workers/"],
        "importance_score": 0.88,
        "tags": ["pattern", "arq"],
    },
]

for memory in migrations:
    response = httpx.post(
        "https://api.neuroloom.dev/api/v1/memories/store",
        headers={"Authorization": f"Token {token}"},
        json={"workspace_id": workspace_id, **memory},
    )
    result = response.json()
    print(f"Stored: {result['id']}  {result['title']}")
curl -X POST https://api.neuroloom.dev/api/v1/memories/store \
  -H "Authorization: Token $MEMORIES_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "'"$MEMORIES_WORKSPACE_ID"'",
    "title": "pgvector HNSW non-transactional behaviour",
    "memory_type": "incident",
    "narrative": "pgvector HNSW index is non-transactional. Rollback does NOT undo index updates. Use DELETE/TRUNCATE for test cleanup, not transaction rollback.",
    "concepts": ["pgvector", "HNSW", "transactions", "testing"],
    "source_files": ["api/neuroloom_api/"],
    "importance_score": 0.95,
    "tags": ["gotcha", "testing", "pgvector"]
  }'

Output:

Stored: mem-1a2b3c4d  pgvector HNSW non-transactional behaviour
Stored: mem-5e6f7g8h  SQLAlchemy workspace isolation requirement
Stored: mem-9i0j1k2l  ARQ job serialization constraint

Step 3: Verify retrieval — search by meaning

Before removing anything from CLAUDE.md, confirm each migrated section is retrievable by the kinds of queries that would arise naturally during a session.

Use memory_search with query "what happens when I roll back a pgvector transaction in tests"
Use memory_search with query "how do I avoid cross-tenant data in queries"
Use memory_search with query "how to pass data to background jobs"
for query in \
  "what happens when I roll back a pgvector transaction in tests" \
  "how do I avoid cross-tenant data in queries" \
  "how to pass data to background jobs"; do
  echo "Query: $query"
  curl -s -X POST https://api.neuroloom.dev/api/v1/memories/search \
    -H "Authorization: Token $MEMORIES_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d "{
      \"workspace_id\": \"$MEMORIES_WORKSPACE_ID\",
      \"query\": \"$query\",
      \"limit\": 3
    }" | python3 -c "
import sys, json
data = json.load(sys.stdin)
for r in data['results']:
    print(f'  {r[\"score\"]:.2f}  {r[\"title\"]}')
"
  echo ""
done

Expected output:

Query: what happens when I roll back a pgvector transaction in tests
  0.94  pgvector HNSW non-transactional behaviour

Query: how do I avoid cross-tenant data in queries
  0.96  SQLAlchemy workspace isolation requirement

Query: how to pass data to background jobs
  0.91  ARQ job serialization constraint

All three sections surface as the top result. If any query returns a score below 0.7, the narrative needs more concept keywords. Add concepts or expand the narrative before proceeding.


Step 4: Configure session context injection

The plugin injects high-importance memories automatically at session start. Configure which memories get injected by importance threshold.

Memories with importance_score >= 0.9 appear in session context by default. The workspace isolation invariant (1.0) and the pgvector rollback gotcha (0.95) both qualify.

To verify injection is working, start a new Claude Code session and ask:

Use session_start, then list what memories were injected

You should see the high-importance memories from your migration in the injected_memories list.

For the full list of available tools and configuration options, see MCP Tools Reference.


Step 5: Trim CLAUDE.md to behavioral rules only

Once all migrated sections retrieve correctly, remove them from CLAUDE.md. Keep only the content that must be present in every session regardless of context:

Keep in CLAUDE.md:

  • Workflow rules ("use sdlc-plan before implementing new features")
  • Tool constraints ("always use AskUserQuestion for decisions")
  • Agent dispatch instructions ("never implement code yourself — dispatch domain agents")
  • Rules that are process, not knowledge

Move to Neuroloom (already done):

  • Architecture decisions with context and reasoning
  • Coding patterns and conventions
  • Bug fixes and gotchas
  • Environment and configuration knowledge
  • Historical context and rationale

Before and after comparison:

Before: 340 lines (~24,000 tokens loaded every session)
After:  85 lines (~6,000 tokens) — behavioral rules only

Knowledge moved to Neuroloom: 47 memories, searchable and session-injected

Step 6: Confirm the agent retrieves context without the old bulk

Open a fresh Claude Code session — one that loads the trimmed CLAUDE.md. Ask a question that would have previously required the full CLAUDE.md:

What do I need to know about running tests against pgvector?

With the old CLAUDE.md, Claude Code would answer from the loaded context. With Neuroloom:

Use memory_search with query "pgvector test isolation gotchas"

Response:

{
  "results": [
    {
      "id": "mem-1a2b3c4d",
      "title": "pgvector HNSW non-transactional behaviour",
      "score": 0.94,
      "summary": "Rollback does NOT undo HNSW index updates — use DELETE/TRUNCATE for test cleanup"
    }
  ]
}

The knowledge is there. It arrives when asked — not loaded into every session.


Production Patterns

Incremental migration — don't cut everything at once

Migrate one section at a time over two weeks. Verify retrieval for each section before removing it from CLAUDE.md. Run both simultaneously during the transition period:

Week 1: Migrate architecture decisions and conventions. Keep them in CLAUDE.md too.
Week 2: Verify all migrated sections retrieve correctly. Remove from CLAUDE.md.
Week 3: Migrate patterns, `incidents`, and gotchas. Same process.
Week 4: Trim to behavioral rules only. Final verification.

The dual-source period means no knowledge is at risk if retrieval turns out to be unreliable for a particular topic.

Rate memories from the first week of use

The first week after migration is the highest-value feedback window. Every time a migrated memory is retrieved and used, rate it positive. Every time a search returns the wrong memory for a natural question, investigate and improve the narrative.

Use memory_rate after each retrieval:

Use memory_rate with memory_id "mem-1a2b3c4d" and useful true and context "Correctly told me not to use rollback in the pgvector test fixture"

Set importance_score thoughtfully

Not everything that was in CLAUDE.md deserves high importance. Apply this heuristic:

ImportanceUse case
1.0Security invariants, workspace isolation, breaking constraints that cause production bugs if forgotten
0.9–0.95Gotchas that cost 30+ minutes to debug, conventions that affect every PR
0.8–0.89Patterns and decisions that are useful frequently but not always
0.7–0.79Historical context, rationale, and background knowledge
Below 0.7Nice-to-know; surfaces in targeted search but not session injection

Periodic cleanup

After 6 months, some memories become stale — the gotcha got fixed, the convention changed, the architecture decision was reversed. Use the memory timeline to find old memories and review them:

curl -X GET "https://api.neuroloom.dev/api/v1/memories/?workspace_id=$MEMORIES_WORKSPACE_ID&created_before=2025-10-01&limit=50" \
  -H "Authorization: Token $MEMORIES_API_TOKEN"

Archive or update stale memories. A growing list of outdated memories degrades search quality.


Before You Ship

  • Verify every migrated section retrieves with score > 0.80 before removing it from CLAUDE.md
  • Confirm importance_score: 1.0 is set only on genuine invariants (2–5 per project is normal)
  • Test session context injection — start a fresh session and confirm the right memories appear
  • Keep behavioral rules in CLAUDE.md — migrate knowledge, not process instructions
  • Tag all migrated memories with "migrated-from-claude-md" so you can audit them later
  • Run the final verification: open a session with the trimmed CLAUDE.md, ask questions about every major topic, confirm Neuroloom answers correctly

Ready to get started?

Start building with Neuroloom for free.

Start Building Free