5-Minute NAMS Quickstart

A hands-on, five-minute walkthrough: install, configure, store some memory, and retrieve it — using the hosted Neo4j Agent Memory Service (NAMS) backend.

By the end of this tutorial you’ll have a Python script that stores messages, an entity, and a reasoning trace in the hosted NAMS service, and reads them back via portable Cypher. You won’t run any database — NAMS handles that for you.

What you’ll need

  • Python 3.10 or newer.

  • A NAMS API key. Sign up here.

  • About five minutes.

1. Install

In a fresh virtualenv:

uv pip install 'neo4j-agent-memory[nams]>=0.4.0'

Or with pip:

pip install 'neo4j-agent-memory[nams]>=0.4.0'

2. Configure

Set your API key in the environment:

export MEMORY_API_KEY=nams_xxxxxxxxxxxx  # your real key

That’s all the configuration needed. With MEMORY_API_KEY set, MemoryClient() automatically picks NAMS as the backend.

3. Write the script

Create quickstart.py:

import asyncio
from neo4j_agent_memory import MemoryClient


async def main() -> None:
    async with MemoryClient() as client:
        conversation = await client.short_term.create_conversation("tutorial-demo")
        conversation_id = str(conversation.id)

        # Short-term memory
        await client.short_term.add_message(
            conversation_id, "user", "Hi, I'm Alice."
        )
        await client.short_term.add_message(
            conversation_id, "user", "I love Italian food."
        )

        # Long-term memory (entities are supported on NAMS; preferences are bolt-only)
        entity = await client.long_term.add_entity(
            "Alice", "PERSON", description="The user"
        )
        if isinstance(entity, tuple):
            entity = entity[0]

        # Reasoning memory
        trace = await client.reasoning.start_trace(
            conversation_id, "Recommend dinner"
        )
        step = await client.reasoning.add_step(
            trace.id, thought="Alice likes Italian"
        )
        await client.reasoning.record_tool_call(
            step.id,
            tool_name="search",
            arguments={"cuisine": "Italian"},
            result=["Da Mario"],
        )
        await client.reasoning.complete_trace(
            trace.id, outcome="Suggested Da Mario", success=True
        )

        # Read everything back
        conv = await client.short_term.get_conversation(conversation_id)
        traces = await client.reasoning.get_session_traces(conversation_id)

        print(f"Messages: {len(conv.messages)}")
        print(f"Entity stored: {entity.name}")
        print(f"Traces: {[t.task for t in traces]}")


asyncio.run(main())

4. Run it

python quickstart.py

Expected output:

Messages: 2
Entity stored: Alice
Traces: ['Recommend dinner']

5. Inspect with Cypher

NAMS exposes a read-only Cypher endpoint via client.query.cypher. Add this snippet to the script:

        # Portable read-only Cypher
        rows = await client.query.cypher(
            "MATCH (e:Entity {name: $name}) RETURN e.name AS name, e.type AS type",
            {"name": "Alice"},
        )
        for row in rows:
            print(row)

Run again. You should see:

{'name': 'Alice', 'type': 'PERSON'}

The same Cypher query works on bolt too — client.query.cypher is backend-agnostic.

What just happened?

  • MemoryClient() with no arguments inspected the environment, saw MEMORY_API_KEY, and built a NAMS-backed client.

  • Every method call became an HTTPS POST/GET to https://memory.neo4jlabs.com/v1/…​;.

  • NAMS embedded your messages, deduplicated the entity, and stored the trace — all server-side.

  • client.query.cypher ran a read-only query against the hosted graph.

You didn’t touch Neo4j. You didn’t configure embeddings. You didn’t run schema setup. NAMS did all of that.

What now?

Cleanup

Want to wipe your tutorial data? It lives in your NAMS workspace; manage it through the NAMS UI at https://memory.neo4jlabs.com.

For bolt-side cleanup you’d run a MATCH (n) DETACH DELETE n Cypher; on NAMS, that write-Cypher is rejected client-side. Use the NAMS dashboard or clear_session(conversation_id) for individual conversations.