Skip to main content

Overview

NanoClaw Pro uses a two-layer memory system:
  1. CLAUDE.md hierarchy - Structured memory files that load automatically into every conversation
  2. qmd semantic search - A local search engine that finds relevant context from your entire conversation history
Together, these systems ensure your assistant gets smarter over time and remembers context across sessions.

CLAUDE.md Hierarchy

CLAUDE.md files are automatically loaded by the Claude Agent SDK when a conversation starts. NanoClaw Pro organizes these files in a three-level hierarchy:

Global

groups/CLAUDE.mdShared across all conversations

Group

groups/{name}/CLAUDE.mdSpecific to one group

Files

groups/{name}/*.mdNotes and documents

Global Memory

Location: groups/CLAUDE.md Read by: All groups Written by: Main channel only Purpose: Store facts, preferences, and context that apply across all conversations. Example:
# Global Memory

## About Me
- Name: Sarah
- Timezone: America/New_York
- Writing style: lowercase, casual, no em dashes

## Preferences
- Prefers morning check-ins at 7am (not 9am)
- Likes detailed technical explanations
- Uses Obsidian for note-taking

## Current Projects
- Building NanoClaw Pro documentation
- Learning TypeScript and container orchestration
Only the main channel can write to global memory. Other groups can read it but cannot modify it.

Group Memory

Location: groups/{group-name}/CLAUDE.md Read by: That group only Written by: That group only Purpose: Store group-specific context, conversation patterns, and ongoing work. Example for a Dev Team group:
# Dev Team Context

## Team Members
- Alice (lead), Bob (backend), Carol (frontend)

## Active Tasks
- Deploying v2.0 to production (Alice leading)
- Investigating Redis performance issue (Bob)
- Redesigning dashboard UI (Carol)

## Conventions
- Use this group for technical discussions only
- Post deployment updates here
- Code reviews happen in GitHub, not here

File Memory

Location: groups/{group-name}/*.md Read by: That group only (available in working directory) Written by: That group only Purpose: Detailed notes, research, meeting logs, project documentation. Example files:
  • research/competitor-analysis.md
  • notes/daily-log.md
  • meetings/2024-01-kickoff.md
  • projects/website-redesign.md

How Memory Loads Automatically

From src/container-runner.ts:58:
function buildVolumeMounts(group: RegisteredGroup, isMain: boolean) {
  const mounts = [];
  const groupDir = resolveGroupFolderPath(group.folder);
  
  if (isMain) {
    // Main gets project root (for code access)
    mounts.push({
      hostPath: projectRoot,
      containerPath: '/workspace/project',
      readonly: true,
    });
  } else {
    // Non-main groups get global memory (read-only)
    mounts.push({
      hostPath: path.join(GROUPS_DIR, 'global'),
      containerPath: '/workspace/global',
      readonly: true,
    });
  }
  
  // All groups get their own folder as working directory
  mounts.push({
    hostPath: groupDir,
    containerPath: '/workspace/group',
    readonly: false,
  });
}
The Claude Agent SDK is configured with settingSources: ['project'], which automatically loads:
  • ../CLAUDE.md (parent directory = global memory)
  • ./CLAUDE.md (current directory = group memory)
You don’t need to explicitly load CLAUDE.md files — the SDK does this automatically when a conversation starts.
qmd is a local semantic search engine that lets you search your conversation history and notes using natural language.

How qmd Works

  1. You write markdown files to ~/memory/ (context, notes, projects)
  2. qmd embeds them using local AI models (creates vector embeddings)
  3. You search semantically - “what am I working on?” finds relevant notes even if they don’t contain those exact words

Installation

qmd is installed automatically when you run /proactive-agent:
npm install -g @tobilu/qmd --prefix ~/.local

Directory Structure

~/memory/
├── context/
│   └── profile.md          # Your profile and preferences
├── notes/
│   └── daily-log.md        # Daily journal entries
└── projects/
    ├── nanoclaw.md         # Project-specific notes
    └── website.md

Adding Memory

Option 1: Tell the agent to remember something
@Andy remember that I prefer dark mode and VS Code for editing
The agent will:
  1. Append to ~/memory/context/profile.md
  2. Run qmd update && qmd embed to index the new content
Option 2: Manually create files
# Create a new project note
echo "# Website Redesign\n\n## Goals\n- Improve mobile UX\n- Add dark mode" > ~/memory/projects/website.md

# Embed it
QMD_DIR=~/.qmd ~/.local/bin/qmd update
QMD_DIR=~/.qmd ~/.local/bin/qmd embed

Searching Memory

From within conversations: The agent automatically searches memory before check-ins:
// From .claude/skills/proactive-agent/SKILL.md:86
"2. Search memory: QMD_DIR=~/.qmd ~/.local/bin/qmd search 'working on'"
Manually from command line:
# Search for information about current projects
QMD_DIR=~/.qmd ~/.local/bin/qmd search "current projects"

# Find notes about a specific person
QMD_DIR=~/.qmd ~/.local/bin/qmd search "Alice"

# Find deadline-related notes
QMD_DIR=~/.qmd ~/.local/bin/qmd search "deadline friday"

Memory in Proactive Check-ins

Every morning check-in searches memory to personalize questions:
// From .claude/skills/proactive-agent/SKILL.md:82
1. Read ~/memory/context/profile.md for context
2. Search memory: QMD_DIR=~/.qmd ~/.local/bin/qmd search "working on"
3. Send a morning check-in adapted based on memory
Instead of a generic “what are you working on?”, you might get:
gm! three questions:
1. how did the website redesign go yesterday?
2. still focusing on the dark mode feature today?
3. what's one thing you're grateful for?
qmd makes check-ins feel personalized because they reference your actual projects and context.

Memory Persistence Across Sessions

NanoClaw Pro uses the Claude Agent SDK’s session feature to maintain conversation continuity.

Session Storage

Location: data/sessions/{group}/.claude/ Format: JSONL (JSON Lines) transcripts Mounted to container: /home/node/.claude/ From src/container-runner.ts:114:
// Per-group Claude sessions directory (isolated from other groups)
const groupSessionsDir = path.join(
  DATA_DIR,
  'sessions',
  group.folder,
  '.claude',
);
fs.mkdirSync(groupSessionsDir, { recursive: true });

mounts.push({
  hostPath: groupSessionsDir,
  containerPath: '/home/node/.claude',
  readonly: false,
});

How Sessions Continue

From src/index.ts:267:
const sessionId = sessions[group.folder];

const output = await runContainerAgent(
  group,
  {
    prompt,
    sessionId,  // Resume previous conversation
    groupFolder: group.folder,
    chatJid,
    isMain,
  },
  // ...
);

if (output.newSessionId) {
  sessions[group.folder] = output.newSessionId;
  setSession(group.folder, output.newSessionId);
}
Result: Claude remembers what you talked about in previous messages, even after restarting NanoClaw.

Writing to Memory

Automatic Memory Updates

The afternoon wrap-up task automatically updates memory:
// From .claude/skills/proactive-agent/SKILL.md:117
After sending:
- Append to ~/memory/notes/daily-log.md
- Run: QMD_DIR=~/.qmd ~/.local/bin/qmd update && qmd embed

Manual Memory Updates

Updating global memory (main channel only):
@Andy remember globally: team prefers async communication over meetings
This appends to groups/CLAUDE.md. Updating group memory:
@Andy remember: Alice is leading the v2.0 deployment
This appends to groups/{current-group}/CLAUDE.md. Creating notes:
@Andy create a note called "meeting-notes.md" with these highlights:
- Decided to use TypeScript for the new service
- Alice will lead code review process
- Deadline is Friday
This creates groups/{current-group}/meeting-notes.md.

Memory Isolation Between Groups

Groups cannot access each other’s memory. Each group has isolated filesystem mounts.
From the architecture (docs/SPEC.md:55):
Working directory: /workspace/group (mounted from host)
Volume mounts:
  • groups/{name}/ → /workspace/group
  • groups/global/ → /workspace/global/ (non-main only)
Main channel:
  • Can read/write groups/CLAUDE.md (global)
  • Can read/write groups/whatsapp_main/CLAUDE.md (its own)
  • Cannot see other groups’ folders
Dev Team group:
  • Can read groups/CLAUDE.md (global, read-only)
  • Can read/write groups/whatsapp_dev-team/CLAUDE.md (its own)
  • Cannot see main or other groups’ folders
Family Chat group:
  • Can read groups/CLAUDE.md (global, read-only)
  • Can read/write groups/whatsapp_family-chat/CLAUDE.md (its own)
  • Cannot see main, dev team, or other groups’ folders
This isolation prevents accidental data leakage between contexts.

Best Practices

Keep Global Memory Clean

Only store truly universal preferences in groups/CLAUDE.md. Group-specific context belongs in group memory.

Update Memory After Big Changes

When switching projects or roles, update your profile and run qmd embed.

Use Descriptive Filenames

Name files like projects/website-redesign.md, not notes.md, for better searchability.

Review Memory Monthly

Prune outdated context from CLAUDE.md files to keep them focused and relevant.

Troubleshooting

Memory Not Loading

Check file exists:
ls -la groups/CLAUDE.md
ls -la groups/whatsapp_main/CLAUDE.md
Check container mounts:
tail -f logs/nanoclaw.log | grep "Container mount configuration"
You should see mounts like:
/absolute/path/groups/whatsapp_main -> /workspace/group
/absolute/path/groups/global -> /workspace/global (ro)

qmd Search Returns Nothing

Re-embed the collection:
QMD_DIR=~/.qmd ~/.local/bin/qmd update
QMD_DIR=~/.qmd ~/.local/bin/qmd embed
Check collection is registered:
QMD_DIR=~/.qmd ~/.local/bin/qmd collection list
You should see:
memory -> /Users/you/memory
If missing, re-add:
QMD_DIR=~/.qmd ~/.local/bin/qmd collection add ~/memory --name memory
QMD_DIR=~/.qmd ~/.local/bin/qmd embed

Session Not Continuing

Check session is saved:
sqlite3 store/messages.db "SELECT * FROM sessions;"
Expected output:
whatsapp_main|ses_abc123xyz...
whatsapp_dev-team|ses_def456uvw...
Check session files exist:
ls -la data/sessions/whatsapp_main/.claude/
Check container user HOME is correct: Container should mount to /home/node/.claude/, not /root/.claude/.

Build docs developers (and LLMs) love