Migrate a Python application to NAMS

To change an existing Bolt application to NAMS, inventory its operations and data assumptions, replace unsupported paths, then verify the application against a separate workspace.

Prerequisites

  • An application with a passing Bolt baseline and identified memory reads/writes.

  • Python 3.10+ with neo4j-agent-memory[nams]==0.7.0; follow the installation and connection check in Connect a Python application to NAMS.

  • A NAMS sandbox workspace key and a synthetic test dataset. Use a separate workspace for migration tests.

  • A data-migration decision. Keep the source database until any separately planned import and rollback procedure has been verified.

1. Inventory operations before changing configuration

Use the capability matrix as the canonical inventory. Search application code for graph writes, preferences/facts, user registry calls, buffering, consolidation, geospatial queries, schema setup and legacy reasoning traces.

Existing behavior Migration action

Raw read Cypher

Use client.query.cypher; check the query against the target schema and the service’s read policy.

Raw write Cypher or add_relationship

Retain the operation on Bolt or redesign around supported service writes. NAMS has no direct client-created relationship equivalent.

Preference/fact CRUD

Retain Bolt or deliberately redesign application storage. A message containing a preference is not a drop-in replacement for preference records.

client.users and user-scoped reads

Keep application identity/authorization explicit. Check which methods accept and forward user metadata; it is not universal isolation.

Buffering, schema adoption, geocoding or client consolidation

Keep the relevant pipeline on Bolt or replace it with an explicitly supported service/application operation. Do not assume an unavailable operation runs automatically on the server.

Legacy reasoning traces

Verify the hosted step representation. Synthetic trace IDs/task/outcome state are not durable equivalents; see reasoning reference.

If an essential behavior has no supported replacement, finish that design before switching the application.

2. Configure a sandbox connection

Follow Connect a Python application to NAMS and run its message write/readback check. Use explicit NamsSettings for migration code so an unrelated environment variable cannot silently select a different backend.

For applications retaining MemoryClient, the equivalent explicit settings are:

import os
from pydantic import SecretStr
from neo4j_agent_memory import MemoryClient, MemorySettings, NamsConfig

settings = MemorySettings(
    backend="nams",
    nams=NamsConfig(api_key=SecretStr(os.environ["MEMORY_API_KEY"])),
)
client = MemoryClient(settings)

Connect and close this client through its async context manager or application lifecycle.

3. Adapt identifiers, results and readiness

  1. Persist the ID returned by create_conversation; do not continue using its display name as the message session ID.

  2. Handle entity creation correctly: Bolt returns (Entity, DeduplicationResult), while NAMS returns an Entity. Keep backend-specific code explicit when the application needs merge details.

  3. After asynchronous ingestion, use a bounded extraction wait and verify the exact expected entity or session status.

  4. Remove inactive client-side embedding/extraction/resolution settings from the NAMS configuration. Configure an LLM provider separately only for client-side summary or application model work.

  5. Replace combined-context isolation assumptions with explicit retrieval and application authorization. Test a second conversation with different synthetic content.

4. Verify the ported application

Run the following checks in the sandbox and retain the returned IDs and failures:

  1. Store a message and retrieve it by the returned conversation ID.

  2. Start a fresh process and reopen that ID without reseeding its original content.

  3. Store and read an entity through supported operations; if extraction is used, verify its bounded success and timeout paths.

  4. Exercise the application’s model/tool failure path and inspect the recorded hosted steps/tool results.

  5. Test authentication failures, rate limits and unsupported operations. Mock tests should reject unimplemented routes instead of silently returning success.

  6. Confirm that content from another user/conversation is handled by the intended access policy; do not treat the presence of a userId field as proof.

Only switch the application after these application-specific checks pass. The detailed supported operations and exceptions remain in backend capabilities and the Python API reference.

Keep raw-write requirements explicit

client.graph.execute_read currently warns on Bolt; use client.query.cypher as the preferred read accessor. client.graph.execute_write remains the Bolt write path.

Limits and gotchas

  • Changing a backend setting does not transfer the existing Neo4j database; keep the source database until a separately planned import and rollback procedure has been verified.

  • This guide does not promise an unshipped removal version or a NAMS write-Cypher replacement.

  • A nonempty workspace search does not prove a given run’s extraction completed — verify the exact expected entity or session status instead.

  • A successful Bolt test suite is a baseline, not evidence of hosted equivalence.