Connect a Python application to NAMS
To store and retrieve messages through NAMS, configure the Python client with a workspace key and use the conversation ID returned by the service.
Prerequisites
-
Python 3.10+ and a POSIX shell.
-
A data-plane workspace key and the intended NAMS endpoint. Obtain these from your workspace administrator or the dashboard. A key’s permissions and workspace association determine access; two keys can belong to the same workspace.
-
Review backend capabilities before moving existing Bolt code.
This procedure uses the published Python 0.7.0 package. It performs a message write and leaves the test conversation available for inspection.
1. Install the client
Create a directory for the connection check and install the package in its own environment:
mkdir nams-connection-check
cd nams-connection-check
python3 -m venv .venv
source .venv/bin/activate
python -m pip install 'neo4j-agent-memory[nams]==0.7.0'
export MEMORY_API_KEY='nams_replace_with_workspace_key'
export MEMORY_ENDPOINT='https://memory.neo4jlabs.com/v1'
Keep the key out of source control. A workspace header is needed only when required by your deployment; see NAMS settings for explicit precedence and fields.
2. Save a complete connection check
Save this as check_nams.py in nams-connection-check/:
check_nams.pyimport asyncio
from uuid import uuid4
from neo4j_agent_memory import NamsSettings, connect
async def main():
client = await connect(NamsSettings())
try:
conversation = await client.short_term.create_conversation(
f"connection-check-{uuid4().hex[:8]}"
)
conversation_id = str(conversation.id)
content = "Connection check: the workshop starts in Denver."
message = await client.short_term.add_message(
conversation_id, "user", content
)
history = await client.short_term.get_conversation(conversation_id)
assert any(item.id == message.id and item.content == content for item in history.messages)
print(f"Verified message {message.id} in conversation {conversation_id}")
finally:
await client.close()
asyncio.run(main())
Resolve a failed check
-
AuthenticationErrorbefore any request: no key is configured. ExportMEMORY_API_KEY. -
AuthenticationErroron a request (HTTP 401 or 403): confirm the key is current and belongs to the intended workspace, and check the endpoint. -
RateLimitErrororTransportError: the request failed after the transport’s retries.RateLimitError.retry_aftercarries the server’sRetry-Aftervalue when it sent one. Python retries only its configured status/network set; see REST transport behavior for the full status-to-exception mapping. -
NotSupportedErrorwhile porting code: the operation is Bolt-only. Follow the migration procedure.
Configuration and operational scope
The maintained NAMS configuration and environment reference describe constructor arguments, aliases and provider wiring. Use the scope reference before adding user metadata.
Limits and gotchas
-
Configuration alone does not migrate stored data or make all Bolt operations available.
-
The connection check above verifies connection, message storage and readback only — it does not certify entity extraction, long-term search scope or reasoning-trace durability. A conversation’s display name and a user ID are not substitutes for its returned ID.
-
Do not replace a workspace key with an admin key merely to bypass a data-plane failure.
-
No service pricing tier is inferred from a rate-limit or transport error.
-
There is no universal
user_identifierparameter or automatic cross-conversation authorization boundary. -
Workspace database provisioning and bring-your-own-database management are separate administrative service operations. Verify the deployed service’s OpenAPI and workspace permissions before using them; they are not part of this connection check.
-
Client-side extraction, embeddings, resolution, enrichment and geocoding settings do not configure the NAMS extraction service.
Trace NAMS requests
The NAMS transport can wrap each HTTP request in a span named nams.http.request. Its attributes are http.method, http.url, nams.method (the SDK operation, for example list_conversations), nams.protocol, http.status_code and, when the request was retried, nams.retry_count.
In Python 0.7.0, connect() and MemoryClient create the transport without a tracer, so requests made through the client emit no spans. To trace requests, build the lower-level NamsBackend yourself and pass a tracer from get_tracer() (see observability configuration). The backend exposes the same short_term, long_term, reasoning, query and ontology accessors that MemoryClient binds on NAMS:
import asyncio
from neo4j_agent_memory import NamsSettings
from neo4j_agent_memory.nams import NamsBackend
from neo4j_agent_memory.observability import get_tracer
async def main():
settings = NamsSettings()
tracer = get_tracer()
async with NamsBackend.from_config(settings.nams, tracer=tracer) as backend:
conversations = await backend.short_term.list_conversations(limit=5)
print(f"Listed {len(conversations)} conversations")
asyncio.run(main())
With no tracing library installed, get_tracer() returns a no-op tracer and no spans are exported.
Recover from an interrupted tutorial run
The three hosted Python tutorials — Store and read back memory, Activate and restore an ontology and Distil and download a skill — each keep a private ledger under .tutorial-state/. Use its recorded state to decide whether it is safe to start a new run:
| Recorded state | Next action |
|---|---|
No mutation was attempted |
Correct the failed prerequisite, then use the guarded new-run check on the tutorial page. |
Every recorded resource was verified absent |
Keep the ledger as evidence, recheck the lesson prerequisites and use a new run directory. |
Retained/shared resources or cleanup exit |
Have the owner record the actual disposition. This is not an automatic permission to reseed. |
Pending or uncertain mutation |
Use owner reconciliation; do not replay seed or erase the pending operation. The ontology tutorial’s own |
Credential changed |
Use the local inspection/handoff procedure in the tutorial’s "Inspect locally after a credential change" section; authenticated commands remain blocked. |
Each tutorial’s own check-new-run command verifies the ledger before you start a fresh lesson directory; it does not by itself change the disposition above.
See also
Runnable examples in the repository:
-
examples/nams-quickstart/— a conversation, messages, an entity, a reasoning trace,wait_for_extraction()and a read-only Cypher query in one script. -
examples/nams-fastapi/— NAMS memory inside a FastAPI service, with the SDK exceptions mapped to HTTP status codes. -
examples/nams-langchain/— a LangChain agent with hosted memory. -
examples/claude-code-team-memory/— one workspace shared across a team’s editors; see Share team memory with an editor.